API input coercion for query params (Zod preprocess)

Query params arrive as strings, and ad-hoc parsing logic tends to drift across endpoints. I use Zod preprocessors to coerce values like page size and booleans, then validate the result. This keeps the handler readable and makes parsing rules shareable

Prisma transaction with retries for serialization errors

Under real concurrency, even ‘simple’ write paths can hit serialization failures, especially with stricter isolation levels. Instead of pretending it won’t happen, I wrap the transaction in a small retry loop with jitter. I only retry on known transie

Playwright smoke test for auth flow

When auth breaks in the UI, it’s expensive and it always seems to happen at the worst time. I keep one or two Playwright smoke tests that cover the critical path: login, navigate, create something, logout. The goal isn’t to test every edge case; it’s

Testing Express routes with Supertest + Jest

Route tests give me fast feedback about the API contract without needing a full browser. I structure the app so I can import an app instance without binding a port, then use supertest to make requests. The key detail is determinism: stub time and rand

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