How a Cached React Bundle Sent Data to the Wrong Database

We hit a deadline. The backend team migrated to a new API and a new database. The frontend team updated environment variables in AWS Amplify and pushed the code.

The deployment was successful. We closed our laptops. We thought we were done.

We were wrong.

An engineer checked the logs on the old API server. This server was supposed to be dead. It was not. It was receiving real client requests and writing data to the old database.

For two hours, real client data went to the wrong place.

Here is why it happened and how we fixed it.

The Problem

React apps on CDNs like AWS Amplify replace environment variables at build time. When you run a build, the bundler finds every variable and replaces it with a hardcoded string.

The API URL was physically embedded in the JavaScript file.

When we deployed, new users got the new bundle. But existing users with the app open never refreshed. They kept running the old bundle with the old URL hardcoded inside.

Because the old server was still running, these clients received a 200 OK status. Everything looked fine. The failure was silent. Silence is the most dangerous type of bug.

The Three-Layer Fix

We built three layers to ensure this never happens again.

  1. Runtime Configuration We stopped baking URLs into the JavaScript bundle. Instead, we use a config.json file in the public folder. The bundler does not touch this file. The app fetches this file at runtime before it renders. This ensures new sessions always get the correct URL.

  2. WebSocket Notifications A runtime config does not help users with an open tab. We tied our deployment process to our WebSocket server. When Amplify finishes a build, it calls a webhook on our API. The server then pushes a message to all connected clients. If a user is on an old version, a banner appears asking them to refresh.

  3. Cache Management We updated our CloudFront settings. Entry points like index.html and config.json are now set to no-cache. This ensures users always fetch the latest files instead of stale versions from a CDN edge node.

The Lessons

• Build-time config is a trap for values that change between deployments. • Silence is more dangerous than noise. Make old systems fail loudly with a 410 Gone status. • Deadline pressure breaks manual steps. Automate your decommissioning process. • Monitor the things you are turning off, not just the things you are turning on.

Deployment is not just about pushing code. It is about making sure every client ends up running the right code.

Source: https://dev.to/sugan_dev/how-a-cached-react-bundle-sent-production-data-to-the-wrong-database-55n9