Unified rules for selecting, modeling, integrating, and operating NoSQL databases (MongoDB, DynamoDB, Redis) from TypeScript back-ends.
You're building a TypeScript backend and facing that familiar crossroads: MongoDB's flexibility, DynamoDB's scale, or Redis's speed? Choosing wrong means refactoring later. Choosing right transforms your architecture from day one.
Most developers pick NoSQL databases based on hype or familiarity, not actual requirements. The result? MongoDB collections that should be Redis cache entries. DynamoDB tables modeling relational concepts. Redis instances storing complex documents.
This creates three painful scenarios:
These Cursor Rules implement a systematic approach to NoSQL selection and implementation. Instead of database-first thinking, you'll design around read/write patterns, then select the optimal NoSQL engine for each bounded context.
// Before: One database trying to do everything
interface User {
id: string;
profile: UserProfile;
sessions: Session[];
analytics: AnalyticsData[];
cache: CacheEntry[];
}
// After: Right database for each concern
// MongoDB: Complex user profiles
interface DbUserProfile { id: string; profile: UserProfile; }
// DynamoDB: High-volume session management
interface DbSession { pk: string; sk: string; ttl: number; }
// Redis: Hot cache data
// Key: user:123:cache, TTL: 300s
Eliminate Architecture Decisions Paralysis Stop spending hours researching which database to use. The rules provide decision trees based on access patterns, not vendor marketing.
Reduce Context Switching by 60%
Repository patterns and consistent TypeScript interfaces mean you work with findUserById() whether it hits MongoDB, DynamoDB, or Redis.
Cut Integration Time in Half Pre-built patterns for error handling, validation, and observability. No more reinventing database connection patterns for each project.
Prevent Costly Migrations Design for polyglot persistence from day one. Add databases as needed without rewriting existing code.
Without Rules:
// Everything in MongoDB - wrong tool for sessions
const user = await db.collection('users').findOne({
_id: ObjectId(userId),
'sessions.active': true,
'profile.lastLogin': { $gt: yesterday }
});
// Result: Complex queries, poor session performance
With Rules:
// Profile in MongoDB (complex documents)
const profile = await userRepository.findById(userId);
// Sessions in DynamoDB (high-volume key-value)
const sessions = await sessionRepository.findActiveSessions(userId);
// Recent activity in Redis (hot cache)
const activity = await cache.get(`user:${userId}:activity`);
Without Rules:
// Trying to do real-time analytics in document DB
const metrics = await db.collection('events').aggregate([
{ $match: { timestamp: { $gte: lastHour } } },
{ $group: { _id: '$type', count: { $sum: 1 } } }
]);
// Result: Slow queries blocking other operations
With Rules:
// Event storage in DynamoDB (high write volume)
await eventRepository.store(event);
// Real-time metrics in Redis (sub-millisecond reads)
await metricsCache.increment(`events:${event.type}:${hour}`);
// Historical analysis in MongoDB (complex aggregations)
const trends = await analyticsRepository.getTrends(dateRange);
# Download and save as .cursorrules in your project root
curl -o .cursorrules https://path-to-rules/nosql-selection-rules.json
// src/users/users.types.ts
interface User {
id: string;
email: string;
profile: UserProfile;
}
interface DbUserProfile {
_id: ObjectId;
email: string;
profile: UserProfile;
version: number;
}
// src/users/users-repository.ts
export class UserRepository {
async findById(id: string): Promise<Option<User>> {
// Cursor will suggest proper error handling,
// validation, and connection patterns
}
}
// Before writing any database code, define this:
const USER_ACCESS_PATTERNS = {
// High frequency, simple lookups → Redis
authenticate: { frequency: 'high', complexity: 'simple' },
// Medium frequency, complex queries → MongoDB
getProfile: { frequency: 'medium', complexity: 'complex' },
// High volume writes, time-series → DynamoDB
trackActivity: { frequency: 'high', complexity: 'simple', volume: 'high' }
} as const;
As you type, Cursor will suggest:
// Cursor automatically suggests proper patterns:
import { z } from 'zod';
import { Result } from 'neverthrow';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
});
export async function findUser(
id: string,
signal: AbortSignal
): Promise<Result<User, AppError>> {
// Error handling, validation, and database-specific
// optimizations suggested automatically
}
Week 1: Architecture Clarity
Week 2: Performance Gains
Month 1: Scaling Confidence
Ongoing: Maintenance Freedom
These rules don't just help you write better database code—they fundamentally change how you approach backend architecture. You'll stop fighting your databases and start leveraging their strengths.
Your next TypeScript backend will have the right database for every job, type-safe operations throughout, and the flexibility to scale each component independently. That's the difference between good code and great architecture.
You are an expert in NoSQL (MongoDB Atlas, Amazon DynamoDB, Redis), Node.js 18+, TypeScript 5+, AWS CDK/Terraform, Docker, and GitHub Actions.
Technology Stack Declaration
- Datastores: MongoDB Atlas (document), Amazon DynamoDB (key-value/wide-column), Redis/Memcached (in-memory cache), S3 (large object off-load).
- Runtime: Node.js 18+, TypeScript 5+, ESM modules only.
- Infrastructure: Docker (local dev), AWS CDK or Terraform (IaC), GitHub Actions (CI/CD).
- Observability: OpenTelemetry, AWS CloudWatch, MongoDB Atlas Alerts, Prometheus/Grafana.
- Security: AWS KMS, MongoDB KMS, HashiCorp Vault for secrets.
Key Principles
- Data models are derived from read/write access patterns, NOT from the relational paradigm.
- Use polyglot persistence: choose the optimal NoSQL engine per aggregate/bounded context.
- Keep schemas flexible but versioned; evolve via additive changes and background migrations.
- Prefer idempotent, stateless functions / handlers; avoid shared mutable state.
- Fail fast: validate inputs, check pre-conditions, return typed errors early.
- Everything is Infrastructure-as-Code and test-covered; manual console edits are forbidden.
- All code and infra changes require automated security + performance gates in CI.
TypeScript Rules
- Strict mode ("strict": true) is mandatory; no implicit any; no namespace; use ES2022 modules.
- Use `interface` for DTOs, `type` for unions & generics; prefix DB models with `Db` (e.g., `interface DbUser`).
- Repository pattern per aggregate root; repositories expose only pure functions (`async function findUserById(id: string): Promise<Option<User>>`).
- Use `zod` or `io-ts` for runtime schema validation; types must be derived (`z.infer`) to avoid drift.
- Async/Await only; never mix with `.then()` in the same scope.
- Top-level `await` in ESM is allowed only in bootstrap files (`src/index.ts`).
- Always pass explicit `AbortSignal` to data-access calls.
- Directory convention (kebab-case):
src/
├─ users/
│ ├─ users-repository.ts
│ ├─ users-service.ts
│ ├─ users-routes.ts
│ └─ users.types.ts
└─ shared/
└─ …
Error Handling and Validation
- Wrap every DB operation in a try/catch; map vendor errors → domain errors via `neverthrow` Result pattern.
- Early return on error; no deep nesting.
- All thrown errors MUST implement `AppError` (`{ message; code; status; cause? }`).
- Use circuit-breakers (opossum) for downstream dependencies; expose `CB_OPEN` errors.
- Validate request payloads at the edge (API Gateway / Express middleware) – reject asap.
- Emit structured logs (JSON) with `errorId`, `db`, `collection/table`, and `queryKey`.
MongoDB Atlas Rules
- Store each aggregate root in its own collection; avoid joins/`$lookup` in hot paths.
- Always define compound indexes from most-to-least selective fields based on read patterns.
- Enable schema validation in Atlas (strict mode) mirroring TypeScript DTO; validationLevel = moderate.
- Use Change Streams to propagate events; never poll.
- Shard on a high-cardinality field aligned with query patterns (e.g., `tenantId`). Avoid monotonically increasing shard keys.
- Transactions: limit to <= 3 collections; max 60 seconds; fallback to eventual consistency where possible.
Amazon DynamoDB Rules
- One table per service pattern.
- Composite primary key: `PK` (partition) + `SK` (sort). Encode entity type prefixes (e.g., `USER#123`).
- Use GSIs for alternative access patterns; project only required attributes.
- Prefer DynamoDB Streams + Lambda for async fan-out.
- Enforce IAM fine-grained access: least privilege per function.
- Use On-Demand capacity for unpredictable traffic; switch to Provisioned + Auto-Scaling for stable workloads.
- Store large blobs (>400 KB) in S3; keep a pointer in DynamoDB.
Redis/Memcached Caching Rules
- Treat cache as disposable; design for cache-miss.
- Key scheme: `<service>:<model>:<id>`; include version or invalidate with `SCAN` + pattern delete on schema change.
- TTL: 3× expected update frequency; never infinite.
- Use Redis Cluster for > 100 GB datasets; enable client-side sharding.
Additional Sections
Testing
- Unit tests: mock DB driver (mongodb-memory-server, dynalite) – 100% critical path coverage.
- Component tests: spin up real Docker containers via Testcontainers; seed minimal data.
- Load tests: k6 scenarios mirroring top 5 read/write patterns; SLO: p95 < 50 ms.
- CI: GitHub Actions matrix (Node 18/20), run `npm run test:ci && npm run lint && npm run typecheck`.
Performance
- Benchmark queries monthly; store explain plans in `/perf/explain-<date>.json`.
- Enable MongoDB Atlas Performance Advisor & apply suggested indexes weekly.
- DynamoDB "hot partition" alerts: > 3000 RCUs/WCUs per partition key per second.
Security
- All secrets via environment variables referenced from AWS Secrets Manager / Vault; never commit `.env`.
- Enable encryption-at-rest (AES-256) & in-transit (TLS 1.2) for all datastores.
- Configure IAM roles with MFA; no inline IAM policies.
Deployment
- IaC is source of truth; PR required for every change.
- Blue/Green or Canary releases with automatic rollback on p99 latency regression > 20%.
- Atlas clusters in M10+ tier; DynamoDB global tables in critical regions (us-east-1, eu-west-1).
Documentation
- Each repository includes `/docs/data-model.md` with ER diagrams, access patterns, index list.
- Run `npm run docs` (TypeDoc) to publish API docs to GitHub Pages.