Skip to content

Your first sqlrs workflow

sqlrs makes experiments against reproducible SQL database states easier. Instead of preparing a shared database by hand, you describe a recipe. Local can prepare an immutable state from that recipe and create isolated, mutable instances for development, tests, and migration checks.

Object Meaning
Workspace A project directory containing local .sqlrs/ configuration. It bounds the files a recipe may use.
Prepare recipe A command and its SQL files, psql includes, or Liquibase changelogs. It must fully describe the database you need.
State The immutable result of a prepare recipe. Local can reuse it while the image, arguments, and input files remain unchanged.
Instance A mutable database derived from a state. Tests and applications change the instance without changing the state or another instance.

The repository stores migrations, SQL, and a short description of how to execute them. Prepared states remain derived local data. Local materializes them when needed, reuses a matching result, and manages them within its cache.

Install the archive for your platform, start its documented container runtime, and open a terminal in a learning project:

sqlrs init local --snapshot auto
sqlrs status

A ready setup reports status: ok, a local profile and mode, the current workspace, and an available container runtime. Endpoint and cache values depend on the machine.

sqlrs prepare:psql --image postgres:16 -- -c "create table if not exists smoke_check(id int); insert into smoke_check values (1);"

A successful prepare prints DSN=postgres://…. Everything after DSN= is the connection string for the new mutable instance. Do not commit it. Arguments after -- belong to psql; sqlrs uses the image, normalized arguments, and input content when identifying the prepared state.

Inspect both sides of the model:

sqlrs ls --states
sqlrs ls --instances

Run the same prepare command again. Because the recipe did not change, Local can reuse its prepared state while returning a new mutable instance. Changes in one instance do not reach the other.

Real recipes normally use one of these paths:

  • prepare:psql for SQL files, psql commands, and \i or \ir include chains;
  • prepare:lb for a root Liquibase changelog and its included changelog files.

First make the raw form work:

sqlrs prepare:psql -- -f db/prepare.sql

Then store the command as a repository-tracked alias:

sqlrs alias create test-db prepare:psql -- -f db/prepare.sql
sqlrs prepare test-db

Commit test-db.prep.s9s.yaml; do not normally commit .sqlrs/. If you do not yet know where the relevant SQL, changelog, or settings live, run sqlrs discover. Discovery reads the project and suggests next steps; it does not create recipes, change configuration, or run migrations.

For one SQL check, combine prepare and run. Local removes the temporary instance after psql exits:

sqlrs prepare test-db run:psql -- -f tests/db-smoke.sql

For a debugging session or several checks, keep the instance and address it explicitly:

sqlrs prepare test-db
sqlrs ls --instances
sqlrs run:psql --instance INSTANCE_ID -- -f tests/db-smoke.sql

For an application or ordinary test runner, pass the DSN from prepare through the environment. The existing-tests chapter provides PowerShell and POSIX examples.

sqlrs rm INSTANCE_ID_PREFIX
sqlrs rm --dry-run --recurse STATE_ID_PREFIX

Use dry-run before recursive deletion. A state with instances or child states is protected without --recurse; with the flag, Local evaluates the whole subtree before deleting anything. --force may remove an instance with active connections, but it does not imply recursive deletion.

  1. Set up Local and your project.
  2. Choose the source of a prepared state.
  3. Inspect a repository with discovery.
  4. Connect an existing test suite.
  5. Compare and prepare Git revisions.
  6. Diagnose common problems.