Your monolith isn't broken. It's just... tired. Every deploy feels like defusing a bomb. A typo in billing takes down auth. Sound familiar? You don't need microservices because Netflix uses them. You need them because your team velocity has flatlined and your blast radius is the entire application.
The 2026 Stack: Boring Is Better
Stop chasing the shiny framework. Production-grade Node.js microservices in 2026 standardize on two runtimes: NestJS for teams wanting structure, decorators, and built-in DI; Fastify for teams prioritizing raw throughput and low overhead. Both support TypeScript natively, OpenAPI generation, and structured logging via Pino. Express is legacy. Koa is niche. Pick one, enforce it org-wide, and move on.
Communication: Sync for Queries, Async for Everything Else
HTTP/REST is fine for external APIs and read-heavy queries. For internal service-to-service? It creates temporal coupling and cascading failures. Use gRPC with Protocol Buffers for synchronous commands — contract-first, schema-enforced, 7-10x faster than JSON over HTTP. Use Kafka (or Redis Streams for simpler needs) for domain events: OrderPlaced, PaymentFailed, UserRegistered. Services emit; they don't care who listens. That's decoupling.
Data: Ownership Over Sharing
Shared databases are distributed monoliths. Each service owns its data — period. Need data from another service? Subscribe to its events and build a local read model (CQRS-lite). Duplicate user_id and email in Orders service? Yes. It's not denormalization; it's autonomy. Use Transactional Outbox Pattern (write event + business data in same DB transaction) to guarantee eventual consistency without 2PC.
Resilience: Design for Failure, Not Success
Networks partition. Dependencies degrade. Implement timeouts (3s default), retries with jitter (exponential backoff, max 3), circuit breakers (open after 50% errors in 10s), and bulkheads (isolate thread pools per downstream). Libraries: @nestjs/terminus for health checks, opossum for circuits. Log every failure with correlation IDs. Trace everything with OpenTelemetry → Jaeger/Tempo.
"A microservice that can't fail gracefully isn't a service. It's a landmine.
— Platform Lead, Fintech Unicorn
Deployment: Kubernetes Is the Runtime, Not the Goal
Containerize with distroless or Alpine base images. Multi-stage builds. Non-root user. HEALTHCHECK in Dockerfile. Deploy via Helm charts or Kustomize. Set resources.requests/limits (CPU: 500m/1000m, Mem: 256Mi/512Mi baseline). Enable HorizontalPodAutoscaler on custom metrics (queue lag, RPS). Use Service Mesh (Istio/Linkerd) only when mTLS, traffic splitting, or fine-grained authz are required — not Day 1.
| Concern | Tool/Pattern | Why |
|---|---|---|
| Service Discovery | CoreDNS + k8s Services | Zero config, built-in |
| Config/Secrets | External Secrets Operator + Vault | GitOps-friendly, rotation |
| Observability | OpenTelemetry + Prometheus + Grafana | Vendor-neutral, standard |
| CI/CD | ArgoCD / Flux | GitOps, progressive delivery |
| API Gateway | Kong / Envoy / AWS ALB | Rate limit, auth, routing |
When NOT to Split
Team < 8 engineers? Single deployable. Domain boundaries unclear? Monolith first. Latency budget < 50ms end-to-end? Keep it together. Microservices add operational tax: distributed tracing, contract testing, deployment choreography, debugging across 10 pods. Pay that tax only when coupling cost exceeds coordination cost.
✦
Your move: Pick one bounded context with clear ownership and high change rate. Scaffold a NestJS service with gRPC, Kafka consumer, OpenTelemetry, and Helm chart. Deploy to staging. Add contract tests (Pact). Measure lead time for change. If it drops — keep going. If it spikes — stop. Architecture serves velocity. Nothing else.










