Faster Schema Tests with PostgreSQL Template Databases
Atlas schema tests run each test group against a fresh copy of your schema on the dev database: Atlas builds the desired schema, runs the group, and tears it down again so nothing leaks between cases. On large schemas, rebuilding the schema for every group dominates the run time. On PostgreSQL, Atlas can instead use a template database, making per-cycle setup near-constant no matter how large the schema is: typically 10x-20x faster end to end, and up to dozens of times faster for larger schemas.
Schema testing and template databases are available only to Atlas Pro users. To use this feature, run:
atlas login
How It Works
With template = true set on the dev block:
- Every test group runs on a fresh copy of the desired schema (plus the optional
baseline). Setup time per group is near-constant, no matter how large the schema is. - All DDL and DML performed by a test is isolated to its own copy and discarded when the group ends.
- Tests marked
parallel = trueshare a single fresh copy, and every non-parallel test gets its own copy, so sequences, inserts, and schema changes never bleed between cases. - Cluster-level role changes are isolated too: roles a test creates are removed, and baseline roles a test alters or drops are restored.
Docker-Managed Dev Database
The simplest way to opt in is to add template = true to a docker "postgres" block and point
your environment's dev at it:
docker "postgres" "dev" {
image = "postgres:18"
template = true
}
env "test" {
src = "file://schema.sql"
dev = docker.postgres.dev.url
}
Given a schema:
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL
);
And a few tests that show the per-group isolation (users_table_exists runs in the shared
parallel copy, while insert_is_isolated and fresh_copy each get their own):
test "schema" "users_table_exists" {
parallel = true
exec {
sql = "SELECT count(*) FROM information_schema.tables WHERE table_name = 'users'"
output = "1"
}
}
test "schema" "insert_is_isolated" {
exec {
sql = "INSERT INTO users (name) VALUES ('alice')"
}
exec {
sql = "SELECT count(*) FROM users"
output = "1"
}
}
test "schema" "fresh_copy" {
exec {
sql = "SELECT count(*) FROM users"
output = "0"
}
}
Run the tests:
atlas schema test --env test
-- PASS: users_table_exists (0.01s)
-- PASS: insert_is_isolated (0.01s)
-- PASS: fresh_copy (0.01s)
PASS
fresh_copy sees zero rows even though insert_is_isolated inserted one because each group ran
on its own fresh copy of the schema.