Safeguard
Developer Tools•

How do you reset a test database between runs without leftovers?

Reset test databases with rollbacks, truncation or throwaway containers so no test data lingers. Here is how to pick and what each leaves behind.

Safeguard Security Team
4 min read

Reset a test database by running each test inside a transaction you roll back, by truncating tables between runs, or by starting a throwaway database container per run. Choose the method that matches your isolation needs, then confirm that nothing outlives the job, including sequences, caches and files.

Why reset matters for data handling

Leftover rows are the quiet way test data lingers. A shared staging database that is never reset collects records from every run, including any real values someone pasted in to reproduce a bug. A strict reset routine caps how long any record can exist and makes deletion a default rather than a chore.

The GDPR principle on storage limitation asks that identifiable data be kept no longer than necessary for its purposes. This is general information, and your counsel should interpret it for your case.

Three approaches compared

ApproachHow it worksStrengthWatch for
Transaction rollbackEach test opens a transaction and rolls back at the endFast, nothing committedCode that commits on its own, or uses a second connection
Truncate between testsTRUNCATE empties tablesSimple, covers committed dataOrder of tables, foreign keys, identity counters
Throwaway containerA fresh database instance per runCleanest, nothing sharedStartup time, image contents

The PostgreSQL documentation states that TRUNCATE is transaction safe with respect to table data: the truncation is rolled back if the surrounding transaction does not commit. It also says that with RESTART IDENTITY the sequence restarts are done transactionally too, though it warns about side effects on sequence functions inside a failed transaction. That makes truncation inside a transaction a workable pattern for suites that need a clean slate.

For the container route, the Testcontainers project describes providing lightweight, throwaway instances of common databases for tests. When the container stops, the data goes with it, provided you did not mount a persistent volume.

Steps for a reliable reset

  1. Decide the unit. Reset per test, per suite or per pipeline run. Per run is a sensible floor.
  2. Load from the seed script. After the reset, load the known fake dataset. Never restore a production dump as the baseline.
  3. Cover all stores. Reset caches, search indexes, message queues and object storage buckets used by tests, not just the SQL database.
  4. Avoid persistent volumes for CI databases unless you have a reason. If you need one, schedule a wipe.
  5. Fail on leftovers. After the suite, run a check that counts rows in key tables. A nonzero count in a table that should be empty is a failed build.
  6. Log the reset. Record job identifier, time and the outcome, so you can show it later.

Shared staging is different

A long lived staging environment cannot reset after every test. Give it a refresh schedule instead, wipe and reseed weekly or nightly, and document the interval. See the related post on how long staging data should live.

Mistakes to avoid

  • Relying on rollback while the code under test opens a separate connection that commits.
  • Truncating tables but leaving uploaded files in a bucket.
  • Forgetting identity counters, which then leak how many records earlier runs created.
  • Pointing the reset script at the wrong host. Add a name check, as in the seed script post.

Quick check

Is rollback enough to delete data?

For data written inside the rolled back transaction, yes. It does not cover anything committed by another connection, files written to disk, or messages sent to other systems.

Does truncate leave traces?

Table rows are removed, but database logs and backups may still hold earlier content for their own retention periods. Check how long those are kept.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.