postgres

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

SQL upsert for counters (ON CONFLICT DO UPDATE)

Counters are classic race-condition bait. If two requests read, increment, and write, you’ll lose updates under load. I prefer letting Postgres do the atomic work with an upsert: INSERT ... ON CONFLICT ... DO UPDATE to increment the existing value. Th

Guard Against Slow Queries with statement_timeout

A per-request statement_timeout is a great “seatbelt” for endpoints that can run bad queries when parameters are unexpected. You can set it for a block; Postgres enforces the wall clock limit.

Read Replica Routing for GET-Heavy Endpoints

For apps with replicas, route read-only code paths to reading role and enforce prevent_writes. This is a strong reliability move: accidental writes on replicas become exceptions instead of silent data loss.

Idempotency keys for “create” endpoints

Retries are inevitable: mobile clients, flaky networks, and load balancers will resend POST requests. Without idempotency you end up double-charging or double-creating records. I store an Idempotency-Key with a sha256 hash of the request body and the

Postgres advisory lock for one-at-a-time work

Sometimes you just need ‘only one worker does this thing at a time’, and building distributed locks from scratch is risky. Postgres advisory locks are a pragmatic option when your DB is already the source of truth. I derive a deterministic lock key (l

Database Views for Read Models

Some read paths want a denormalized shape without materializing a new table. Postgres views are a clean option. Keep the view definition in a migration and map it with a read-only model.

Partial index for “active” rows in Postgres

Not all queries benefit from a full-table index, especially when most rows are ‘inactive’ or archived. A partial index lets you index only the subset you care about (like active users or un-deleted records), which shrinks index size and improves cache

SQL migration safety: add column nullable, backfill, then constrain

The fastest way to surprise yourself in production is ADD COLUMN ... NOT NULL DEFAULT ... on a large table. My safe pattern is: add the column nullable with no default, backfill in batches, then add the NOT NULL constraint. If I need a default for new

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

Transactional Outbox for Reliable Event Publishing

I used a transactional outbox when I needed my database write and my event publish to succeed or fail together. In OutboxEvent model, I treated the outbox like a queue: a durable row per event, a dedupe_key for idempotency, and a ready scope that pull

DB-Level “no overlapping ranges” with exclusion constraint

Scheduling/booking is tricky. Postgres exclusion constraints prevent overlapping time ranges at the database layer—far more reliable than application checks. Rails can still validate, but the DB is the source of truth.