Optimistic toggle button with Stimulus “revert on failure”

I like optimistic UI for tiny interactions (like “star” or “follow”) because it makes the interface feel instant. The tradeoff is handling failure cleanly. I implement this with Stimulus: flip CSS + text immediately, then submit a Turbo request in the

Turbo Frame modal that renders server HTML

When I need a modal (new/edit/show), I avoid client-side templating by using a dedicated turbo_frame_tag as the modal container (often id='modal'). Links target that frame, so the response only replaces the modal content. Closing the modal is just swa

Inline edit a table row with Turbo Frames

For admin-ish UIs, inline editing is the best balance of speed and clarity. I wrap each row in a turbo_frame_tag keyed by dom_id(record) and render either a read-only row partial or an edit form partial inside the same frame. Clicking “Edit” targets t

Turbo Stream flash messages without custom JS

Instead of sprinkling custom JS for notifications, I treat flash as UI state and render it via Turbo Streams. When a create/update succeeds, the controller responds to format.turbo_stream and the template uses turbo_stream.replace to swap the flash co

Frontend: normalize and display server validation errors

Server-side validation is the source of truth, but raw error payloads are rarely UI-friendly. I normalize validation errors into a Record<field, message> shape so forms can render them consistently. The tricky detail is mapping server field path

Vite env handling: explicit prefixes only

Leaking secrets into the browser bundle is an easy mistake. Vite only exposes env vars with the VITE_ prefix, and I keep that rule strict. I also define a small typed wrapper so components don’t read import.meta.env directly everywhere. The wrapper gi

Prettier config for consistent formatting

Formatting consistency matters, but humans shouldn’t be the ones enforcing it in code review. Prettier makes diffs smaller and reviews more focused on logic. I keep the config minimal and aligned with team expectations (singleQuote, trailing commas, ~

ESLint config that avoids bikeshedding

I want linting to catch bugs, not fuel style debates. I use ESLint for correctness rules (unused vars, no-floating-promises, React hooks rules) and let Prettier handle formatting. I keep overrides minimal and justified. I also treat lint as part of CI

Next.js bundle analyzer for targeted performance work

Performance work is hard when you’re guessing what’s in your bundle. The bundle analyzer turns it into a visual diff: you can see which dependencies are big and whether code splitting is working. I gate it behind an env var like ANALYZE=true so it’s o

Response compression (only when it helps)

Compression can dramatically reduce payload sizes for JSON and HTML, but it also costs CPU. I enable it with sane defaults and avoid compressing already-compressed content (like images). Compression can also hurt streaming responses and SSE, so I disa

Security headers with helmet (baseline hardening)

Most security issues aren’t exotic—they’re missing headers and unsafe defaults. helmet gives a sensible baseline: headers that reduce clickjacking risk, tighten content-type sniffing, and improve general browser hardening. I still configure CSP explic

Multipart upload streaming (busboy)

Multipart uploads can blow up memory if you parse them naively. With busboy, I stream file data as it arrives and enforce size limits and content-type checks early. I avoid writing to disk unless I need it; for many flows I stream directly to object s