Stop Using Real Customer Records in Staging

The production dump in staging is the most convenient decision a team can make and the one most likely to end up in an incident report. It is worth being precise about why, because “it’s a privacy risk” is vague enough to be argued with.

Last updated: 30 August 2026 · Tools SoShareIT editorial team

What changes when data leaves production

Production is where the controls are. Access is restricted, changes are audited, backups are encrypted, and someone can tell you who read what and when. That is not an accident of where the database sits — it is the accumulated result of everyone treating it as the place that matters.

Staging inherits the data and none of the controls. The same customer records now sit somewhere with broader access, looser logging, and a backup policy nobody has reviewed. The data did not become less sensitive by being copied. Only the protection around it did.

Under most data protection regimes that copy is still processing personal data, and “it was only staging” is not a category the law recognises. The obligations follow the data.

Four ways it goes wrong

Mail escapes

Staging points at a real mail provider because somebody needed to test the welcome email, and the sending guard is one environment variable that gets flipped during debugging and not flipped back. Real customers receive test mail — sometimes an order confirmation for an order that does not exist.

Redaction tape peeling from paper illustrating why anonymisation is often not enough

This is the most common one and the most visible, because the customers tell you.

Access widens quietly

Staging credentials are shared more freely than production ones, precisely because everyone believes staging is not sensitive. Contractors get access. Credentials end up in a wiki page, or a repo, or a screenshot in a chat thread. Every one of those is now a route to your customer list.

Backups nobody owns

Production backups are encrypted, rotated and monitored. The staging snapshot somebody took before a risky migration sits in object storage with a permissive bucket policy and no expiry. Two years later nobody remembers it exists, which is exactly the state in which such things are found by other people.

Screenshots and demos

Staging is where screenshots come from. Documentation, bug reports, sales demos, conference talks. Every one is a small, permanent, uncontrolled disclosure of a real customer’s name, address or order history, and unlike the database it cannot be deleted after the fact.

Why anonymisation usually isn’t

The standard answer is to scrub the dump. It is better than nothing and it is weaker than it sounds, for two reasons that are easy to miss.

Blank white tiles in a grid illustrating generated test data as the alternative

Scrubbing is a blocklist, and blocklists rot. The script masks the columns someone thought of when they wrote it. Then a feature adds delivery_notes, where customers type their phone number and gate code, and nobody updates the script because nobody connects a new column to a scrubbing job in a different repository. Six months later the free-text field is the leak.

Structure identifies people even when fields are masked. Replacing a name with User 4812 leaves the purchase history, the timestamps and the postcode. For any customer with an unusual pattern — and there are always some — the record is still recognisable to anyone who knows them. Genuine anonymisation is a hard technical problem, and a search-and-replace over a few columns is not a solution to it.

The alternative, concretely

Generate the data instead. The objection is always that generated data is not realistic enough to find real bugs, and that objection is usually about the wrong kind of realism.

What your code needs is structural fidelity: postcodes that match their country, leading zeros preserved, accented characters that survive the round trip, fields at their length limits. None of that requires a real person’s details, and a deliberately seeded fixture covers those cases better than a production dump does — the dump contains whatever your customers happen to be, not what breaks your code.

The practical build is covered step by step in our guide to seeding a staging database with test addresses. The short version:

  • Postal codes generated per country from the real format — the generator on Tools SoShareIT covers 15 of them.
  • Email addresses on example.com, so a stray send reaches nobody.
  • Hostnames on .test and IP addresses in 192.0.2.0/24, which belong to no one by design.
  • Phone numbers in the reserved 555-0100 to 555-0199 block.
  • A fixed random seed, so a failing row can be regenerated exactly.

The result is a staging environment you can screenshot, share with a contractor, and forget a backup of, without any of those being an incident. That is the actual benefit — not compliance paperwork, but the ability to stop thinking about it.

Frequently asked questions

Is copying production data to staging actually illegal?

It is not automatically illegal, but it is still processing personal data, and every obligation that applied in production follows the copy. Most regimes expect the protection to travel with the data; “it was only staging” is not a recognised category. If you would not export the same records to a spreadsheet on a laptop, the staging copy deserves the same answer.

Isn’t anonymised production data good enough?

It is better than nothing and weaker than it sounds. Scrubbing scripts are blocklists that rot — a new free-text column appears and nobody updates the job in the other repository. And masking a name leaves the purchase history, timestamps and postcode, which still identifies anyone with an unusual pattern.

Won’t generated data miss real bugs?

It misses a different set, and usually a smaller one. Production dumps contain whatever your customers happen to be, not what breaks your code. A deliberately seeded fixture covers leading zeros, length limits and encoding edge cases better, because those rows are chosen rather than hoped for.

What about performance testing? Doesn’t that need real data?

It needs real shape, not real people. Clustering and skew are what determine whether a query plan uses an index. You can reproduce the distribution — the long tail, the hot keys — without a single real name attached to it.

Where do I start if we already have production data in staging?

Find the backups first. Live staging databases get replaced eventually; the snapshot somebody took before a risky migration two years ago sits in object storage with no expiry and no owner, and that is the copy that gets found by other people.