Node.js Microservice Patterns
Service boundaries, event-driven communication, retries, idempotency.
# CLAUDE.md — Node.js Microservice Patterns
## Boundaries
- One service per **bounded context**, not per table or per resource.
- A service owns its data. No service reads another service's database directly — always through an API.
- If two services constantly co-deploy and co-change, they're one service.
## Communication
- **Sync** (HTTP/gRPC) for queries that need an immediate answer.
- **Async** (events, queues) for state propagation — orders → inventory, user-created → email-welcome.
- Default to async. Sync calls between services create cascade failures.
## Idempotency
- Every mutation accepts an idempotency key. Same key = same response, even on retry.
- Implement with a key→result table indexed on the key. TTL old keys.
- Without idempotency, retries (yours or the client's) duplicate work. There will be retries.
## Events
- Schema-first. Use **Avro**, **Protobuf**, or at least a **JSON Schema** registry.
- Events are immutable facts: `OrderPlaced`, `PaymentSettled`. Past tense.
- Emit on commit, not on intent. Outbox pattern: write the event row in the same DB transaction as the state change; a separate process publishes from the outbox.
## Failure handling
- Retries are bounded: 3–5 attempts with exponential backoff and jitter.
- After max retries, send to a **dead-letter queue**. Alert on DLQ growth.
- Circuit breakers (`opossum` or hand-rolled) on every cross-service call. Fail fast when downstream is unhealthy.
## Observability
- **Distributed tracing** with OpenTelemetry. Propagate `traceparent` across HTTP, queues, and async hops.
- Structured logs with `trace_id` and `span_id` on every line.
- Per-service metrics: requests/sec, p99 latency, error rate, queue depth.
## Versioning
- API versioning in the URL or header. `v1` is forever; `v2` is additive at first.
- Producer compatibility for events: only **add** fields, never remove or rename. Consumers tolerate unknown fields.
## Service mesh / gateway
- An API gateway terminates TLS, does auth, and routes. Services trust the gateway's auth claims.
- Mesh (Istio, Linkerd) for mutual TLS and traffic policies. Don't reinvent in app code.
## Local development
- One docker-compose per service group. New devs `docker compose up`.
- Stub external services with **wiremock** or **mockoon**.
- Don't run all services on every laptop. Run the ones you change; talk to a shared dev environment for the rest.
## Don't
- Don't share databases across services to "save effort". You're trading short-term convenience for long-term coupling.
- Don't expose internal IDs across service boundaries. Use stable UUIDs.
- Don't synchronously call N services to assemble a response. Aggregate via materialized views or a BFF.
- Don't deploy services together as a unit. The whole point is independent rollout.
Other TypeScript templates
Next.js App Router + TypeScript Rules
Server Components, Server Actions, and TypeScript discipline for the Next.js App Router.
Next.js + Server Actions + Shadcn UI
Forms with Server Actions, Zod validation, and Shadcn UI primitives.
Next.js + Supabase Auth
Auth flows with Supabase SSR, cookies, and Row Level Security policies.
Next.js + Tailwind + Prisma Stack
Full-stack Next.js with Prisma ORM, Tailwind CSS, and Postgres.
Next.js SEO + Metadata Rules
Metadata API, sitemap, robots, OG images, and structured data done right.