Health checks with readiness + liveness

One /health endpoint is ambiguous: is the process alive, or is it actually ready to serve traffic? I split them. Liveness answers ‘should the orchestrator restart me?’ and is usually just ‘the event loop is alive’. Readiness answers ‘can I accept traf

Docker multi-stage build for Next.js

A single-stage Dockerfile tends to ship your entire build toolchain into production, which makes images bigger and slower to deploy. I prefer multi-stage builds: one stage installs deps + builds, the final stage runs only the minimal production output

GitHub Actions: cache + tests + build

CI has to be fast enough that developers don’t bypass it. I cache npm’s package store so we’re not re-downloading the world every run, and I split lint / test / build into separate steps so failures are obvious and logs are readable. The other non-neg

API pagination response contract (page info)

For list endpoints, the frontend needs predictable pagination metadata, not just an array. I return items plus pageInfo (endCursor, hasNextPage) so building infinite scroll is straightforward and the API stays extensible if you later add totals (which

Feature flags with a typed registry

Ad-hoc feature flags turn into a mess of magic strings faster than most teams expect. I keep a typed registry so flags are discoverable and refactor-safe, and I resolve them centrally (user/org/rollout percentage) instead of scattering logic across co

Streaming CSV import (Node streams)

The first time a CSV import OOM’d a production process, I stopped trusting ‘just read it into memory’. Now I stream the upload to disk (or S3), stream-parse rows, and batch inserts into the DB. The win is that memory usage stays flat, even when the fi

Safe markdown rendering (remark + rehype)

Markdown is the sweet spot for user-generated content: expressive enough, but not a full HTML editor. The danger is letting raw HTML slip through. I use remark to parse markdown, then rehype to render HTML, and I disable raw HTML unless I have a sanit

Sanitize user HTML safely (DOMPurify + JSDOM)

Letting users paste rich content is a product requirement that can become a security nightmare. I never try to write my own sanitizer. Instead, I run HTML through DOMPurify using JSDOM on the server and keep the allowlist small (minimal tags + attribu

Prometheus metrics for request latency

During an incident, the first question is usually ‘is it getting worse?’, and log lines don’t answer that well. Prometheus-style metrics make it easy to track rates and percentiles over time. I instrument request duration as a histogram and label by m

API error shape that frontend can rely on

Inconsistent error responses cause death-by-a-thousand-cuts on the frontend. If one endpoint returns a string, another returns nested objects, and a third throws HTML, you end up with messy UI conditionals everywhere. I use a small set of stable error

Pre-signed S3 upload from the browser

Large file uploads don’t belong on app servers. My default is: the server issues a short-lived pre-signed URL, the browser uploads directly to S3, then the server stores the object key. That keeps latency low and costs predictable. Before signing, I v

CSRF protection with double-submit cookie

Session-based apps still need CSRF protection even when the API is ‘JSON’. I like the double-submit cookie approach: set a CSRF token cookie, require the client to echo it in x-csrf-token, and verify they match. The reason I prefer this is that it doe