Skip to main content

CLI reference

snoutdata is one bundled file with no dependencies, so npx snoutdata is a download rather than an install. It needs Node 20 or newer.

note

Published on npm as snoutdata. Nothing to install: npx snoutdata <command> fetches it and runs it.

The rules every command follows

--jsonAccepted everywhere. Exactly one JSON value on stdout and nothing else, so a pipe into jq needs no filtering. Progress and warnings go to stderr.
No promptsNothing asks a question when stdin is not a terminal. A command that would have to ask says which flag to pass, and exits 2.
Unknown flagsAn error, never ignored.

Exit codes

CodeMeaning
0Fine.
1The operation failed.
2The command was wrong (a bad flag, a missing argument, no project).
3The credential is no good: never signed in, expired, or revoked. The message says which.
4Not ready yet. Retrying is reasonable.
127A program this command needs is not installed (psql, or pg_restore for an archive).

Where things come from

A token, in this order:

  1. SNOUTDATA_ACCESS_TOKEN
  2. ~/.snoutdata/auth.json, written by snoutdata login

The environment wins deliberately, so a script does not behave differently depending on who is logged in on the machine running it.

A project, in this order:

  1. --ref
  2. SNOUTDATA_PROJECT
  3. .snoutdata/project.json in this folder or any parent, walked upward the way git finds .git, so the CLI works from a subdirectory.

A password: never typed. Commands that run psql or pg_restore fetch the project's credentials because you are signed in and pass the password to the child process in its environment, never on a command line.

Global flags

FlagDoes
--jsonJSON on stdout, nothing else.
--helpPrint the usage summary.
--versionPrint the version.

Every command

init

snoutdata init [--name NAME] [--region REGION] [--env] [--ref REF]

From nothing to a working DATABASE_URL. Creates a project (named after the current folder unless --name says otherwise), waits until it is serving, writes .snoutdata/project.json, and with --env writes DATABASE_URL into .env.

Idempotent: a folder that is already linked prints that project's URL instead of creating a second one. The .env line is rewritten in place rather than appended, so you never end up with two DATABASE_URLs.

login, logout, whoami

snoutdata login [--provider github]
snoutdata logout
snoutdata whoami

login opens a browser and completes a PKCE flow against a loopback callback. The provider defaults to google. The session it writes lasts an hour and is refreshed automatically.

whoami says who the credential belongs to and which door it came in by, a session or an access token.

tokens

snoutdata tokens list
snoutdata tokens create --name NAME [--expires DAYS]
snoutdata tokens revoke <id|sdt_prefix>

tokens create prints the token on stdout, alone, once. Only its hash is stored, so there is no second call that returns it. Without --expires it does not expire.

A token cannot create another token. A token can revoke itself, or any other.

projects

snoutdata projects list
snoutdata projects create --name NAME [--region REGION] [--team NAME|ID] [--no-wait]
snoutdata projects pause [--ref REF]
snoutdata projects resume [--ref REF]
snoutdata projects delete [--ref REF]

create waits for the project to be ready unless you pass --no-wait, because a connection string handed over before the database exists is a string that does not work yet. It prints the connection URL once; snoutdata db url prints it again any time.

--team takes a team name or a team id. A name that matches more than one team is refused rather than guessed at.

A projects list row shows read-only rather than ready when the project is over its storage limit, because that is the state you need to know about.

teams

snoutdata teams

The teams you can share a project into. A team you can see but cannot share into is listed with the reason, rather than hidden.

snoutdata link --ref REF

Writes .snoutdata/project.json in the current folder, so later commands here need no --ref.

db url

snoutdata db url [--ref REF]

Prints the postgres:// connection string on stdout, one line, nothing else. It contains a live password.

If the project is over its storage limit, a warning goes to stderr so it cannot end up inside a .env line.

db psql

snoutdata db psql [--ref REF] [-- PSQL ARGS...]

Opens psql against the project. Everything after -- is passed to psql verbatim.

Needs psql on the machine. If it is missing, the error says so and points at db url.

db reset-password

snoutdata db reset-password [--ref REF]

Prints a new password for the project's role. It applies when the project restarts with it, which the command says out loud rather than implying the change is instant.

db export

snoutdata db export [--ref REF] [--out FILE]
snoutdata db export --status [--ref REF]

Asks the control plane for a pg_dump, waits for it, and either prints a signed download link or, with --out, streams the dump to that file.

  • Asking twice is one export. A second request while one is running is treated as the same request, so a script that retries does not queue a second pg_dump against a production database.
  • --status looks without asking, which is what you want when the alternative is running a dump against somebody's live database.
  • A missing link is not a failed export. Links are signed with credentials that rotate every few hours, so an aged-out one is dropped rather than handed over dead. The dump is still there; asking again signs a fresh link against the same file.

db push

snoutdata db push [--dir DIR] [--dry-run] [--out-of-order]

Runs every .sql file in the folder (migrations by default), in byte-wise name order, once each, recording what ran in a _snoutdata_migrations table in your own database.

Order is ls | sort, so zero-pad your numbers (001-, 002-) or 10- sorts before 9-.

The ledger row is written in the same transaction as the migration, so a file that fails half way leaves nothing behind and there is no state where the database believes something ran that did not. A file that cannot be wrapped in a transaction says so on a line of its own, and db push tells you it has given that guarantee up:

-- snoutdata:no-transaction
create index concurrently people_email_idx on people (email);

It refuses three things, and overrides only one:

It refusesBecauseOverride
A file that changed since it ranThe database and the folder now disagree about what happened, and the old statements have already run. The fix is a new migration.none
A file that has goneUsually a rename, and a rename is how the same SQL runs twice.none
A new file that sorts before one already appliedTwo branches merge and 003 lands after 004 ran, which gives this database a history no fresh database will ever have.--out-of-order

Every problem is reported at once, not one per run. --dry-run says what would happen and changes nothing.

Needs psql, because a migration connects to the database like any other client.

db restore

snoutdata db restore --file DUMP [--ref REF] [--force]

Puts a dump into a project. The other half of db export.

The format is sniffed from the file's first bytes, not from its name, because pg_dump writes four formats and a file called .dump may be any of them. A custom or tar archive goes to pg_restore, plain SQL to psql, and a file that is neither is refused rather than guessed at.

It refuses a database that already has tables, because the overwhelmingly likely cause is the wrong --ref. --force is for when you mean it. It also refuses a project that is over its storage limit, and --force does not get past that one: every write would fail anyway.

Restoring an export of ours into a project of ours produces errors about not owning pg_stat_statements. Those are expected, nothing is missing, and the command says so instead of failing. Any other error is still a failure.

Needs psql, and pg_restore as well for an archive.

usage

snoutdata usage [--ref REF] [--days N] [--history]

Size, compute and connections against the plan's limit. --days defaults to 30 and is capped at 365. --history prints the day-by-day table underneath.

first light (x8x3sb2hcx4xn)
7.7 MB of 8.0 GB on plus (0%).
Over 2 days: 1d 6h of compute, 2 connections.

A dash in the size column is a day nothing measured it, which is what a paused project looks like. It is not zero, and the current size is the most recent day that has a reading. Compute and connections are summed, because there a missing day really did have none.

mcp

snoutdata mcp [--allow-delete]

Serves the same operations to an agent over stdio. See for an agent.

Environment variables

VariableDoes
SNOUTDATA_ACCESS_TOKENThe credential to use. Wins over ~/.snoutdata/auth.json.
SNOUTDATA_PROJECTThe project ref to act on, when there is no --ref.
NO_COLORTurn off the bold and dim escape codes. Colour is off anyway when stdout is not a terminal.