THE BL<G>
Deep dives into modern web technologies, architectural patterns, and the ever-evolving landscape of software engineering.
The Day PostgreSQL Row-Level Security Broke My API
Adding Row-Level Security to PostgreSQL seemed smart — until every API request started returning empty arrays and users thought their data was deleted.
The Day Next.js Middleware Destroyed My SEO
A simple middleware to handle authentication created a redirect loop that got 15,000 pages de-indexed from Google in 48 hours.
The Kubernetes Rollout That Almost Ruined Black Friday
A simple kubectl rollout restart on Black Friday caused a 47-minute outage and $340,000 in lost sales — all because of a missing readinessProbe.
The Expo OTA Update That Broke Offline Mode for 10,000 Users
An innocent OTA update changed how AsyncStorage worked, causing 10,000 offline users to lose their data and making the app crash on launch.
The Next.js Server Action That Leaked User Emails to Google
A Server Action that fetched user profiles returned HTML with email addresses in the response, and Google indexed them all within hours.
The 2.3GB Docker Image That Killed Our Deploys
A Node.js Docker image grew to 2.3GB, causing 25-minute deploys and $500/day in extra costs — until we discovered multi-stage builds.
The Push Notification That Woke Up 50,000 Users at 3 AM
A misconfigured cron job sent "Good morning!" notifications at 3 AM to 50,000 users. The uninstall rate went up 800% in 24 hours.
The Unhandled Promise Rejection That Killed Our Node.js Server
One missing .catch() caused our Node.js server to crash 47 times in one night. Each crash took 30 seconds to recover — 23 minutes of downtime total.
The Day Git Saved My 2 Hours of Work
A failed Husky pre-commit hook made me think I lost 18 files and 2 hours of work — until I discovered how Git stash saved everything.
The MongoDB Aggregation Pipeline That Killed Our CPU for 3 Hours
A single aggregation pipeline with $lookup and $unwind brought our MongoDB CPU to 100% for 3 hours — all because of missing indexes and bad pipeline ordering.
The Prisma findUnique That Returned null (But the Data Existed)
A Prisma query kept returning null for records that definitely existed. The culprit? A case-sensitive UUID comparison between PostgreSQL and Node.js.
The Next.js Static Export That Generated 50,000 404 Pages
Setting output: "export" in Next.js seemed simple until Google indexed 50,000 404 pages because of a trailing slash mismatch.
The GitHub Actions Secret That Printed to Logs (And We Rotated All API Keys)
A debug echo command printed our AWS secret key to GitHub Actions logs. Within 3 minutes, someone tried to launch 50 EC2 instances on our account.
The Expo Build That Failed Because of Metro’s Symlink Resolution
Using Yarn workspaces with Expo caused Metro to fail with "Unable to resolve module" – but only on CI, never locally. It took 2 days to find the symlink issue.
The PostgreSQL Check Constraint That Silently Corrupted User Data
A poorly written CHECK constraint accepted invalid data but rejected valid updates, corrupting 10,000 user records without any error message.
The Next.js Image Optimization That Brought Down Our Vercel Deployment
Adding next/image to 500 product images seemed fine until Vercel started timing out during build – because each image triggered a remote fetch.
The Docker Volume That Accumulated 200GB of Logs (And Killed the Server)
A Docker container wrote logs to an anonymous volume. 6 months later, that volume had 200GB of log files and brought the entire server down.
The React Native FlatList That Re-rendered 1,000 Times Per Second
A FlatList with 2,000 items started re-rendering every frame, dropping to 5 FPS. The cause: an inline arrow function passed to renderItem.
The PERN Stack Authentication That Accepted Any Password (For 3 Days)
A typo in bcrypt.compare made it return true for any password. 1,200 user accounts were accessed without authorization before we caught it.
The MongoDB Shard Key That Made 99% of Queries Scan Every Shard
Choosing the wrong shard key turned our 10-shard cluster into a broadcast storm – every query hit all shards, and response times went from 50ms to 5 seconds.
The Prisma Migration That Dropped a Production Column (No Way to Recover)
A Prisma migration that looked safe – renaming a column – turned into a silent data loss because we forgot to add a @map attribute. 50,000 rows lost their values.
The Next.js Parallel Route That Caused an Infinite Loop (And Killed the Server)
Parallel routes in Next.js 14 seemed perfect for a dashboard layout – until a missing default.js file created an infinite rendering loop that maxed out CPU.
The Docker Network That Leaked Host Ports (And Exposed Redis to the Internet)
Using 'network_mode: host' on a Redis container seemed convenient – until we realized it exposed Redis directly to the public internet without authentication.
The Expo Splash Screen That Never Hid (And Users Thought the App Was Frozen)
A misconfigured splash screen stayed visible forever on Android because we forgot to call 'SplashScreen.hideAsync()' after an async operation that threw an error.