Comparisons / Test harnesses
Testcontainers tests fixtures; RowShield verifies production
The short version
- Testcontainers spins up disposable Postgres instances per test run so integration tests exercise real SQL against real engine behaviour. RowShield continuously inspects and probes the deployed Supabase project itself.
- Choose Testcontainers when — you are building application integration tests and want disposable, realistic databases in CI.
- Choose RowShield when — your worry is the live system — who can read what right now, and what changed since yesterday.
RowShield rules relevant here
- criticalRow Level Security disabled
- criticalPolicy always evaluates to true
- criticalTable readable with the anon key
Head to head: Testcontainers vs RowShield
| Capability | Testcontainers | RowShield | Edge |
|---|---|---|---|
| Subject under test | A Postgres container built from fixtures and seed data seconds earlier — genuine engine, carefully constructed world. | The actual project serving traffic, including every dashboard edit and restore regardless of what passed through CI. | RowShield |
| Schema source | Whatever migrations the harness applies in order — faithful to your files, blind to anything applied outside them. | The catalog as deployed today, drift included: console hotfixes and manual policy edits are part of the picture. | RowShield |
| Policy realism | Only as good as the fixture policies someone keeps synchronised by hand; lapses in that sync are silent. | Live pg_policies read from the server itself and evaluated by shipped rules, so realism is measured rather than assumed. | RowShield |
| Anon-key behaviour | Simulatable if a test mints an anon client against fixture data; rarely simulated in real suites. | Probed for real via GET against the deployed PostgREST, using exactly the key every visitor already holds. | RowShield |
| CI integration maturity | Excellent — lifecycle-managed containers per test run is the entire point of the library, and it shows. | A CLI with clean exit codes for gating; between runs, scheduling is handled for you without any pipeline involvement. | Testcontainers |
| Language ecosystem | Java-first heritage with strong modules for other runtimes; needs a container runtime wherever tests execute. | Any stack that can hold a connection string; the probe speaks plain HTTP and the CLI is one Node dependency. | Parity |
| Cost profile | Open source; costs concentrate in harness code and the container runtime that feeds it. | Free tier covers daily scans; paid plans are what you move to when you need hourly verification. | Testcontainers |
Column claims about Testcontainers are sourced below. Where the edge is theirs, the page says so — and the sections that follow explain why Supabase teams still pick RowShield.
What Testcontainers does
Testcontainers libraries start Dockerised databases (and brokers, browsers, caches) scoped to test lifecycles. For Postgres this means migrations run against genuine engine versions, flaky-mock problems disappear, and parallelism is cheap.
Mechanically, a test requests a Postgres container, receives mapped port and credentials, applies migrations or init scripts, runs its assertions through a real client, then lets the container be discarded. Startup, reuse and teardown are managed for you, which is why suites built this way tend to stay deterministic where mocked databases drifted.
It is superb engineering infrastructure — and by construction it validates a world you constructed: fixtures, seed data, policies copied into the harness.
Where the scopes differ
Everything Testcontainers proves lives left of the deploy. Post-deploy is where Supabase posture actually breaks: dashboard-side policy edits, restores, manual hotfixes, generated migrations nobody diffed. Containers cannot see that universe.
Behavioural truth differs too. Fixture anon-keys in tests follow fixture policies; the probe asks the running PostgREST what the public key fetches today — filtered-versus-empty ambiguity included honestly.
There is also a fidelity chain worth naming: container behaviour matches your migrations, migrations match your intentions, and intentions match production only while every change flows through git. Supabase projects routinely break that last link — the SQL editor, storage settings and provider restores all mutate state without commits.
Why Supabase teams choose RowShield over Testcontainers
Not instead — for the other half of the timeline. Teams adopt RowShield because post-merge changes bypass CI constantly, because findings arrive with fixes rather than logs, and because drift classification (created/regressed/resolved) turns posture into a monitored property instead of a hope.
Onboarding is deliberately shallow next to harness work: connect the project, schedule scans, route alerts to the channel the team already reads. There is no harness to version and no runtime to provision, which matters for backend teams who never wanted to own test infrastructure at all.
Cost-wise, one project on the Free tier covers what a homegrown prod-check harness would eat sprint weeks building.
Where Testcontainers is the right choice
Application-layer integration testing — repositories, query builders, transaction logic, migration correctness before merge — deserves real engines, and Testcontainers is the best-in-class way to get them. Nothing here argues otherwise; we would rather teams ran honest containers than trusted mocks.
If your deployment story guarantees every change passes through reviewed migrations, the container world approximates production closely, and the gap narrows further. The pivot arrives with the first out-of-band change — a dashboard edit, a restore, an agent patch — after which most teams conclude that fixtures verify intent while RowShield verifies reality, and keep both.
Using both
Standard pairing: Testcontainers in CI proving app-plus-SQL correctness on fixtures; RowShield in production proving the deployed system stays safe as humans and agents change it. Different subjects, complementary schedules, zero overlap in blame. When the two disagree, treat it as signal: either the harness drifted from production or production drifted from intention, and both deserve investigation before anyone shrugs.
Frequently asked
- Is RowShield affiliated with the Testcontainers community?
- No. RowShield is an independent product by Veristria; Testcontainers belongs to its community and is referenced descriptively here because it is the leading way teams put real databases under integration tests. Nothing on this page implies endorsement or partnership, and descriptions rely on publicly documented behaviour only. This page describes scope differences, not the quality of their work.
- Is RowShield a Testcontainers alternative?
- For integration-test orchestration, no — keep Testcontainers, it does that job well. For continuous verification of the deployed database, yes; that is a job no fixture-based container can do, because the subject is the live project rather than a reconstruction of it, and reconstruction is exactly where leaks hide. The two answer different questions about different subjects.
- Can RowShield scan staging too?
- Yes — connect each environment as its own project and each receives its own baseline, findings and history. Team plans monitor up to fifteen projects at fifteen-minute cadence, which comfortably covers a staging-plus-production split alongside preview environments. Because environments are scanned independently, a staging hotfix can never mask a production regression.
Check your project in about ten seconds
Paste a URL. No signup, no writes, nothing stored.
Run the free audit