Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.
Scanned 9/28/2026
Install to Claude Code
npx -y skills add Nmor/the-claude-council --skill backend-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Backend Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/nmor-backend-patterns)More formats (shields.io, HTML) on the badges page.
---
name: backend-patterns
description: Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.
---
# Backend Development Patterns
> **Size budget: 25 KB.** Check: wc -c. Gate: node ~/.claude/scripts/token-budget.mjs --check
Backend architecture patterns and best practices for scalable server-side applications.
> **Reuse-first** (per `~/.claude/rules-library/common/reuse-first.md`):
> Before creating a new service / repository / middleware /
> handler helper / validator / DTO, sweep the project's `lib/`,
> `services/`, `repositories/`, `middleware/`, `validators/`,
> `dto/` (or language-equivalent) directories. One source of
> truth per concept (one auth middleware, one error envelope, one
> pagination helper, one rate limiter, one DB client factory).
> Extend with a parameter — never fork.
## When to Activate
- Designing REST or GraphQL API endpoints
- Implementing repository, service, or controller layers
- Optimizing database queries (N+1, indexing, connection pooling)
- Adding caching (Redis, in-memory, HTTP cache headers)
- Setting up background jobs or async processing
- Structuring error handling and validation for APIs
- Building middleware (auth, logging, rate limiting)
## Pattern Routing Table
The detail lives in `references/`. Load the row you need; do not load the whole set.
| Topic | Covers | Reference |
| --- | --- | --- |
| API design + layering | RESTful URL shape, repository, service layer, middleware | `references/api-layering.md` |
| Database patterns | Query optimization, N+1 prevention, transactions | `references/database.md` |
| Caching strategies | Redis caching layer, cache-aside | `references/caching.md` |
| Error handling | Centralized error handler, retry with exponential backoff | `references/error-handling.md` |
| Authentication and authorization | JWT token validation, role-based access control | `references/auth.md` |
| Rate limiting | Simple in-memory rate limiter | `references/rate-limiting.md` |
| Background jobs and queues | Simple queue pattern | `references/background-jobs.md` |
| Logging and monitoring | Structured logging | `references/logging.md` |
| Fire-and-forget side effects | Canonical helper, usage, wrong-shape test, bug signatures | `references/fire-and-forget.md` |
| Content-hash file caching | SHA-256 cache key, frozen entries, service wrapper, anti-patterns | `references/content-hash-caching.md` |
**Remember**: Backend patterns enable scalable, maintainable server-side applications. Choose
patterns that fit your complexity level.
## Purpose
Server-side architecture patterns for Node.js / TypeScript / Next.js backends: handler structure,
repository / service layering, validation, error envelopes, caching, background jobs, structured
logging, and fire-and-forget side effects.
**Negative scope**: NOT REST contract design (see `~/.claude/skills/api-design/SKILL.md` — that owns
URL shape, status codes, pagination). NOT database schema / migrations (separate skill). NOT cloud
deployment patterns (`~/.claude/skills/aws-serverless-patterns/SKILL.md` covers Lambda specifics).
NOT frontend state management.
## When NOT to use
- Stateless function-as-a-service workloads where Lambda + DynamoDB single-table covers the use case
— use `aws-serverless-patterns`
- Pure database query optimisation — use `postgres-patterns` or `dynamodb-patterns`
- GraphQL servers (their middleware / resolver model differs)
- BFF (backend-for-frontend) layers that are thin pass-through — overengineering risk
- Embedded / batch / CLI workloads with no HTTP surface
## Standards Cited
- **RFC 9110** (HTTP Semantics, Jun 2022) §15 — status code semantics for handlers
- **RFC 9457** (Problem Details, Jul 2023) — error envelope shape
- **OWASP ASVS 4.0.3 §4** (Access Control), §5 (Validation, Sanitisation, Encoding), §7 (Error
Handling + Logging)
- **OWASP API Security Top 10 (2023)** — API1 BOLA, API4 Resource Consumption, API8 Security
Misconfiguration
- **The Twelve-Factor App (12factor.net)** — IV (Backing Services), VIII (Concurrency), XI (Logs)
- **Node.js LTS Documentation** (current LTS) — stream + async patterns
- **Repository / Unit-of-Work pattern** — Fowler, *Patterns of Enterprise Application Architecture*
(2002)
## Anti-Patterns
| Pattern | Why bad | Correct alternative |
| --- | --- | --- |
| Fat handler (DB call + business logic + serialisation in one function) | Untestable; violates single-responsibility; couples HTTP to domain | Handler → service → repository layering |
| DB connection per request (no pool) | Connection exhaustion under load; latency spike on every request | Singleton pool injected at app start; per-request connection acquired from pool |
| Synchronous `for` loop calling DB | N+1 query pattern; serial latency stacks | Batch fetch with `IN (…)` + Map lookup OR JOIN |
| `console.log` for production logging | No structure, no correlation IDs, no filterable severity | Structured logger (pino, winston, slog) with `request_id` + `trace_id` |
| Fire-and-forget `void store.save()` or `.catch(() => null)` | Silent failure; error never surfaces; bug found by user, not on-call | `fireAndForget(name, promise)` helper that logs with operation + cause |
| Caching without TTL + invalidation strategy | Cache becomes permanent stale state; user sees outdated data | Explicit TTL + invalidation hook on mutation |
| Middleware order matters (auth after parsing JSON of any size) | DoS via 100MB body before auth fires | Auth + body-size limit FIRST in middleware chain |
| Webhook handler that mutates state on every retry | Provider retries → double-charge / double-create | Idempotency key + dedupe table (see `~/.claude/rules-library/common/idempotency.md`) |
## Verification Checklist
- [ ] Handler delegates to service; service delegates to repository (3-layer)
- [ ] All input validated via schema (Zod / Joi / class-validator) at boundary
- [ ] Connection pool injected once at app start; never created per-request
- [ ] Structured logger with `request_id` propagated through async context
- [ ] Errors mapped to RFC 9457 envelope at boundary; no internal stack traces leaked
- [ ] No N+1 — every `forEach` over DB rows audited for batch alternative
- [ ] Fire-and-forget uses the canonical helper, never bare `void`/`.catch(() => null)`
- [ ] Cache keys carry version prefix so deploys can invalidate
- [ ] Rate limit + auth middleware fires BEFORE body parsing of unbounded size
## Cross-References
- `~/.claude/skills/api-design/SKILL.md` — REST contract design (URL, status, envelope)
- `~/.claude/rules-library/common/idempotency.md` — Idempotency-Key contract for mutating endpoints
- `~/.claude/rules-library/common/no-silent-failures.md` — fire-and-forget canonical shape
- `~/.claude/rules-library/common/error-handling-with-context.md` — wrap-with-context discipline
- `~/.claude/rules-library/common/rate-limiting.md` — middleware ordering + RateLimit-* headers
- `~/.claude/rules-library/common/no-ambient-globals.md` — connection pool injection vs module-level
singleton
- `~/.claude/rules-library/common/reuse-first.md` — sweep before adding a new middleware /
repository / DTO
- `~/.claude/skills/postgres-patterns/SKILL.md` — query optimisation
- `~/.claude/skills/observability-patterns/SKILL.md` — structured logging + trace propagation
## Why this skill exists
Backend handlers are where every customer-visible failure is born — and where the cost of
correctness is lowest at write time. The recurring failure modes:
- A handler that bundles DB + logic + serialisation grows to 300 lines, becomes untestable, and
accumulates dark corners where validation is missed
- A connection pool created per-request exhausts under modest load (200 concurrent users ×
1s/request = 200 simultaneous connections; Postgres default `max_connections=100`)
- N+1 queries hide in `await Promise.all(items.map(i => fetch(i.id)))` patterns; latency P99
explodes as data grows
- Fire-and-forget side effects (audit logs, peer-tab broadcasts) lose their errors; on-call doesn't
find out for hours
- Webhook handlers fire twice on every provider retry without an idempotency table → double-charges
on Stripe, double-emails on SendGrid
Cost of the layered + structured-logger + idempotent + bounded-middleware pattern: minutes per
handler at write time. Cost of debugging the unstructured version: hours per incident.
## Learning hooks
Per `~/.claude/rules/common/continuous-learning-mandate.md`:
**Signals to watch**:
- Fire-and-forget side effect without `.catch` / structured failure log (sister
`no-silent-failures.md` violation)
- Handler shape duplicates middleware logic that already exists (reuse-first weakening)
- Connection pool created per-request instead of injected from the application root
- DB call inside a loop where a JOIN / batch would work (N+1 pattern)
- Background job triggered synchronously when an outbox + worker would be safer
- Cache without TTL + invalidation strategy (cache becomes permanent stale state)
- Webhook handler not idempotent on retry (sister `idempotency.md` violation)
- Cross-request mutable state introduced (sister `no-ambient-globals.md` violation)
- Content-hash cache used as a write-through path without corruption-as-miss handling
**Refinement candidates**:
- New pattern row when a recurring backend shape emerges (e.g., outbox + transactional events, CQRS
read model, materialized view refresh)
- New cross-reference when a sister rule (idempotency, observability, error-handling-with-context)
adds a server-side gate
- Tightening of the fire-and-forget pattern when async errors slip past structured logging
- New cache-eviction template when a recurring staleness incident class recurs
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!