Actionable rules for enforcing the “Don’t Repeat Yourself” principle across full-stack TypeScript, Python, SQL, Terraform, React, Express, Django and dbt projects.
Your codebase has become a maintenance nightmare. Functions repeated across services, constants scattered everywhere, business logic duplicated between frontend and backend. Every bug fix requires hunting down multiple copies of the same code. It's time to stop the madness.
Here's what happens when DRY principles break down in real projects:
Constants Everywhere: User roles defined in 6 different files. Change "admin" to "administrator" and break half your application because you missed one.
Business Logic Drift: Price calculation logic exists in React components, Express routes, Django views, and dbt models. They all implement it slightly differently. Which one is correct?
Infrastructure Copy-Paste: Every new service gets its own Terraform configuration with 90% identical code. Security updates require touching 12 different files.
SQL Repetition: The same complex joins appear in every analytics query. Performance optimization means updating dozens of scripts.
This isn't just technical debt—it's developer productivity suicide.
These Cursor Rules transform how you handle duplication across your entire stack. Instead of fighting repeated code after it appears, you'll prevent it systematically through smart abstractions, centralized definitions, and automated enforcement.
Key Principle: One authoritative source for every piece of knowledge in your system—whether it's code, logic, data definitions, or infrastructure configurations.
Before: Validation logic scattered across components
// In UserForm.tsx
const validateEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// In api/users.ts
const isValidEmail = (email: string) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
};
After: Single source of truth with Zod schemas
// lib/validation.ts
export const UserSchema = z.object({
email: z.string().email(),
name: z.string().min(2)
});
// Used everywhere
export type User = z.infer<typeof UserSchema>;
Result: 70% fewer validation bugs, instant API/frontend sync, single place to update rules.
Before: Repeated model patterns
# In multiple models
class Article(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
class Product(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
After: Mixin-based composition
class TimestampMixin(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
class Meta:
abstract = True
class Article(TimestampMixin):
title = models.CharField(max_length=200)
Result: 50% less model code, consistent field behavior, easier schema migrations.
Before: Metric calculations duplicated everywhere
-- In 15 different queries
SELECT
user_id,
SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END) as revenue
FROM orders
GROUP BY user_id
After: Centralized metrics via dbt
-- models/metrics/revenue_by_user.sql
{{ config(materialized='view') }}
SELECT
user_id,
{{ calculate_revenue('orders') }} as revenue
FROM {{ ref('orders') }}
GROUP BY user_id
Result: Consistent metrics across all reports, single place to fix calculation bugs, 90% faster new dashboard creation.
Before: Copy-paste Terraform configurations
# Repeated in 8 service directories
resource "aws_s3_bucket" "logs" {
bucket = "service-a-logs"
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
After: Reusable modules
# modules/s3_bucket/main.tf
module "service_bucket" {
source = "./modules/s3_bucket"
name = "${var.service_name}-logs"
tags = local.common_tags
}
Result: 80% reduction in infrastructure code, consistent security policies, 5-minute service setup instead of 30.
Add duplication detection to your CI/CD pipeline:
# .github/workflows/code-quality.yml
- name: Check for duplicated code
run: |
npx jscpd --threshold 3 --reporters console,json
pylint --duplicate-code src/
terraform fmt -check=true
Create centralized locations for reusable code:
/lib/ # TypeScript utilities
/services/ # Business logic
/modules/ # Terraform modules
/macros/ # dbt macros
/mixins/ # Django mixins
Abstract on the third duplication, not the first. This prevents premature optimization while catching real patterns.
Move all constants, feature flags, and environment variables to single configuration files:
// config/constants.ts
export const USER_ROLES = {
ADMIN: 'admin',
USER: 'user',
MODERATOR: 'moderator'
} as const;
export type UserRole = typeof USER_ROLES[keyof typeof USER_ROLES];
Week 1: Automated detection catches 80% of new duplication before it hits production
Week 2: Shared utility libraries reduce new feature development time by 30%
Month 1: Bug fixes that previously required 5+ file changes now touch single source of truth
Month 3: New team members productive 50% faster due to consistent patterns and centralized logic
Ongoing: Maintenance overhead drops dramatically as your codebase becomes self-documenting through consistent abstractions
Allow deliberate duplication across service boundaries to maintain autonomy, but never within services:
// ✅ OK: Simple DTOs duplicated across services
// user-service/types.ts
interface User { id: string; email: string; }
// order-service/types.ts
interface User { id: string; email: string; }
// ❌ Not OK: Complex business logic duplicated
Use tree-shaking and bundle analysis to prevent utility library bloat:
// lib/index.ts - Barrel exports for tree-shaking
export { formatCurrency } from './formatters';
export { validateEmail } from './validators';
// Import only what you need
import { formatCurrency } from '@/lib';
Generate API documentation from your single source of truth:
/**
* Formats monetary values consistently across the application
* @param cents - Amount in cents to avoid floating point issues
* @param currency - Currency code (USD, EUR, GBP)
*/
export function formatPrice(cents: number, currency: Currency): string {
// Implementation...
}
Your codebase transformation starts with implementing these rules. Stop accepting duplication as inevitable—make it impossible instead.
The time you save debugging inconsistent logic and hunting down scattered constants will immediately pay for the setup effort. Your future self will thank you when that critical bug fix touches one file instead of ten.
You are an expert in TypeScript (ES2022+), JavaScript, Python 3.12, SQL (PostgreSQL), Terraform 1.x, Docker, React 18, Next.js 14, Express 5, Django 4, and dbt 1.x.
---
Key Principles
- DRY = a single, authoritative representation of every piece of knowledge (code, logic, data, infrastructure, documentation).
- Eliminate copy-paste; replace with composition, parametrisation, or shared modules.
- Balance DRY with YAGNI: abstract only after the 3rd duplication or when the risk/cost of divergence is high.
- Separate concerns: isolate business logic from I/O, UI, and persistence to maximise reuse.
- Centralise constants, feature flags, environment variables, and error messages.
- Automate enforcement (linters, duplicate-code detectors, schema diffing) in CI/CD.
---
Language-Specific Rules
TypeScript / JavaScript
- **Utilities**: Place pure helpers in `/lib/` and re-export from an `index.ts` barrel.
- **Generics**: Use `function identity<T>(value: T): T { … }` patterns instead of multiple overloads.
- **Enums & Const Objects**: Centralise string literals: `export const Roles = { Admin: 'admin', User: 'user' } as const;`.
- **React Hooks**: Extract repeated state/effect logic into custom hooks (`useFetch<T>(url)`), never duplicate `useEffect` chains.
- **Validation**: Co-locate Zod/Yup schemas with DTOs and reuse on both client and server.
Python
- **Modules**: One responsibility per module; share via import, not copy.
- **Dataclasses & Pydantic**: Reuse validated models across API layers.
- **Mixins & ABCs**: Factor out common ORM/query logic: `class TimestampMixin(models.Model): …`.
- **Scripts**: Convert one-off scripts to `@click.command()` CLIs inside `tools/` to avoid drift.
SQL (PostgreSQL)
- **CTEs & Views**: Wrap complex metrics in materialized views instead of repeating joins.
- **dbt Macros**: `{{ get_date_dim('day') }}` for dynamic date dimensions.
- **Constants Table**: Store business enumerations (`status`, `regions`) in reference tables, not scattered literals.
Terraform
- **Modules First**: Anything repeated twice becomes a module with variables & outputs.
- **Locals**: Use `locals { common_tags = { project = "acme" } }` instead of redefining tags.
- **Remote State**: One state per bounded context to avoid cross-file duplication.
---
Error Handling and Validation
- Create a shared error hierarchy per language (`BaseError`, `ValidationError`, `NotFoundError`).
- Centralise error -> HTTP mapping in a single Express/Django middleware.
- Validate at boundaries (controllers, event consumers) and pass typed, validated objects inward—no re-validation deeper.
- Always log with correlation/idempotency keys from a single tracing utility.
- Early-return on error paths; reserve the indented "happy path" for success flow.
---
Framework-Specific Rules
React / Next.js
- Functional components only; extract UI primitives (`<Button />`, `<Modal />`) into `/ui/`.
- Share layout/state via Context or Zustand; avoid prop-drilling duplicates.
- Use CSS modules or Tailwind; never duplicate inline style objects.
Express (Node)
- Router files contain **only** route mapping; delegate logic to service classes located in `/services/`.
- Common middleware (`auth`, `rateLimit`, `validate`) registered once at the app root.
Django
- Prefer Generic CBVs + mixins (`ListView`, `UpdateView`) over hand-rolled views.
- Reuse querysets with `QuerySet.as_manager()`.
DBT
- All models reference sources via `source()`; never hard-code schemas.
- Macros for repeated filters (`where is_active = true`) and incremental logic.
- Store metrics in YAML `metrics:` blocks; query via `dbt_metrics` to ensure consistency.
---
Additional Sections
Testing
- Shared fixtures/factories in `/tests/conftest.py` or `test/utils.ts`.
- Parametrised tests to cover edge cases without duplicating bodies.
- Snapshot tests for repeatable APIs; regenerate snapshots only via PR-reviewed script.
CI/CD & Tooling
- Integrate `jscpd`, `pylint --duplicate-code`, `terraform validate`, `sqlfluff` in pipelines.
- Block merges when duplication threshold >3% of changed lines.
- Use Renovate/Dependabot to avoid forking library code for patching.
Performance & Architecture
- Microservices: allow **small, deliberate** duplication across services but never share runtime DB tables.
- Frontend bundle-size checks prevent the “utility explosion” anti-pattern; tree-shake shared libs.
Documentation
- Generate API docs from source (TypeDoc/Sphinx) during build, not by hand.
- ADR templates under `/docs/adr/YYYY-MM-DD-short-title.md`; reference in code comments instead of duplicating rationale.
Security
- Central auth module; no repeated JWT verification logic.
- Single configuration file (`.env.example`) listing all env vars; imported via typed config loader.
---
Examples
TypeScript duplicate elimination:
```ts
// Before (duplication)
export function formatPriceUSD(cents: number) {
return `$${(cents / 100).toFixed(2)}`;
}
export function formatPriceEUR(cents: number) {
return `€${(cents / 100).toFixed(2)}`;
}
// After (DRY)
export function formatPrice(cents: number, currency: 'USD' | 'EUR') {
const symbol = { USD: '$', EUR: '€' }[currency];
return `${symbol}${(cents / 100).toFixed(2)}`;
}
```
Terraform module extraction:
```hcl
# ./modules/s3_bucket/main.tf
resource "aws_s3_bucket" "this" {
bucket = var.name
tags = var.tags
}
```
SQL view centralisation:
```sql
CREATE MATERIALIZED VIEW revenue_mv AS
SELECT order_id,
sum(quantity * unit_price) AS gross_revenue
FROM fact_order_lines
GROUP BY order_id;
```
---
Checklist for PR Reviewers
- [ ] No identical or near-identical blocks flagged by CI.
- [ ] All literals/constants moved to shared files.
- [ ] Business logic appears once per bounded context.
- [ ] New abstractions justified by ≥2 prior duplications or clear future reuse.
- [ ] Updated/added tests cover the refactored abstraction.