← ~/blog

Your Staging Environment Is Lying to You

 /  systems  /  297 words

Staging has one job, tell you what will happen in production, and it fails at that job constantly. Ours passed every test the night before a deploy that took checkout down for 40 minutes. Same code. Different everything else.

The lies stack up quietly. Staging runs one replica where prod runs twelve, so you never see the connection pool exhaustion that only happens when twelve pods each open forty connections. Staging's database has 200k rows where prod has 90 million, so your unindexed query runs in 30ms instead of 30 seconds. Staging talks to sandbox versions of third party APIs that respond instantly and never rate limit you. And staging gets one polite synthetic user at a time, never the Saturday spike.

The one that got us was config drift. Someone had bumped a timeout on staging six months earlier while debugging and never backported it. Every test passed against a setting production did not have.

I don't think the answer is making staging a perfect prod replica. You will never afford it, and chasing it burns time you could spend on things that work. What actually moved the needle for us, roughly in order: diffing config between environments in CI so drift fails the build, load testing against a copy of prod scale data even if it only happens quarterly, and shifting most of our confidence from staging to progressive rollouts in prod itself. Canary five percent of real traffic, watch the error rate, promote or roll back. Real users, real data, real dependencies, small blast radius.

Staging still exists here. It catches the dumb stuff early and cheap, does the migration run, does the app boot. I just stopped treating a green staging run as a promise. It is a smoke test with good marketing.