Local development
The same Postgres, on your own machine, in one command:
snoutdata start
It runs a container, applies your migrations, runs your seed, and prints a connection string. Nothing about it touches your account or costs anything, so it is where you develop and where tests run; the hosted project is where you deploy.
For the WHOLE stack (auth, the data API, storage, Realtime and functions as well) in Docker, see Use the CLI with a local stack instead.
It needs Podman and nothing else. The image is public and is pulled on
first use. You do not need psql installed: when the machine has none, the container's own is
used instead, which is what makes this work on a default Windows install.
A new database runs Postgres 18, like a hosted project. One made on 17 keeps
starting on 17: snoutdata start reads the version from the data directory and runs the matching
image, because 18 cannot open files 17 wrote.
Start, stop, status
snoutdata start [--port 54322] [--dir migrations] [--no-migrations] [--out-of-order]
snoutdata stop
snoutdata status
$ snoutdata start
Wrote .snoutdata/local.json. It holds a password, so put .snoutdata/ in your .gitignore.
Database running on port 54322
Migrations 3 applied
Seed seed.sql ran
postgres://postgres:[email protected]:54322/postgres
The URI is the only thing on stdout, so DATABASE_URL=$(snoutdata start) is correct with no
filtering.
stop stops the container and keeps the data: start brings it back as it was. status says
whether it is running, on what port and how big it has got, and answers plainly when there is no
local database for this folder rather than treating that as an error.
--port defaults to 54322. If something else is already on it, pass another port, or you
will get a raw address-in-use error from the container runtime rather than a sentence about it.
Migrations and the seed
A start applies migrations/*.sql in name order, once each, and then seed.sql if there is one.
It uses the same planner snoutdata db push uses: the same ledger table, the same refusals
for a file that changed after it ran or a file that has gone, the same --out-of-order override,
and the same -- snoutdata:no-transaction escape for a statement that cannot be wrapped. There is
deliberately no second planner, because a local database that disagreed with the hosted one about
what "already applied" means would be worse than no local database at all.
--no-migrations skips both. --dir points somewhere other than migrations.
Two projects in one folder
.snoutdata/local.json sits beside the .snoutdata/project.json that snoutdata link writes,
and they do not interfere. A folder can be linked to a hosted project and have a local database
at the same time, which is the ordinary case.
local.json holds a password, so .snoutdata/ belongs in your .gitignore. It is a password
for a database on loopback that nothing off your machine can reach, so this is tidiness rather
than a vulnerability, but the CLI says so the first time it writes one.
TypeScript types from your schema
snoutdata gen types typescript --local > database.types.ts # the local database
snoutdata gen types typescript > database.types.ts # the hosted project
snoutdata gen types typescript --schema public,billing --out src/database.types.ts
The output goes to stdout and nowhere else unless you ask, because the caller is usually a build
script or an agent. Progress goes to stderr, --out names a file, and --json wraps the same
text in one JSON value.
It reads the Postgres catalogs rather than information_schema, which is why an enum column
comes out as its enum and an array as an array, where the portable view says USER-DEFINED and
ARRAY. It is one query and it takes no lock.
Against a hosted project it needs psql on the machine. With --local it does not: it borrows
the container's, like everything else here.
Why Podman and not Docker
Hosted projects run under Podman, rootless, and snoutdata start runs the same image the same way.
File ownership and user mapping are where the two differ, so a database that worked only under
Docker could pass on your machine and fail once deployed. There is deliberately no Docker fallback.
Podman runs on Windows, macOS and Linux, and installs alongside Docker Desktop.
Also read
- Use the CLI with a local stack, for the whole stack in Docker.
- CLI reference, for every flag.
- The project API, for what is in front of the hosted database.