Skip to content

Running in CI

NSchema is built to run unattended and be easy to automate. A few things facilitate this:

  • a strict exit-code contract,
  • opt-in “did anything change?” signals,
  • offline planning that needs no database at plan time,
  • and built-in linting, validation and drifting checks.

Write actions like apply and destroy will prompt for confirmation by default. When running in a non-interactive terminal, like in a build pipeline, nschema will exit 1 and make no changes, unless the --auto-approve flag is specified, this helps protect against executing changes unintentionally:

Terminal window
nschema apply --auto-approve

While the PROVIDER block supports setting the connection string and password directly, it is strongly recommended to provide them via environment variables instead. Connection strings don’t belong in source control:

Terminal window
export NSCHEMA_POSTGRES_CONNECTION_STRING="$DB_CONNECTION_STRING"
# optionally, credentials out of band:
export NSCHEMA_POSTGRES_USERNAME="$DB_USER"
export NSCHEMA_POSTGRES_PASSWORD="$DB_PASSWORD"

See Environment variables.

Providers and backends are plugins: nschema downloads the version pinned in your config the first time a command needs one. In CI that means:

  • The agent needs the .NET SDK and network access to your NuGet feed (the restore shells out to dotnet).
  • More control in provider versioning by pinning versions in your PROVIDER / BACKEND blocks.
  • To control when the fetch happens: fail fast on a bad pin, or warm the cache before timed steps. Run nschema init up front, and pass --no-init to later commands to require the cache and skip any restore.

The plan command always exits 0 by default unless there was an error. If you opt in with--detailed-exitcode, NSchema will return 2 when there are changes, so a check can fail (or comment) when a PR alters the schema:

Terminal window
nschema plan --detailed-exitcode # 0 = no changes, 2 = changes, 1 = error

If a state store is configured, this will run without a database connection. See Offline planning & state.

Fail the build if any .sql file isn’t canonically formatted:

Terminal window
nschema fmt --check # exits 2 if files need formatting, 1 on error

A quick, database-free correctness check, checks syntax and some basic structural checks like missing references or empty tables:

Terminal window
nschema validate

The safest pipeline splits planning from applying: by saving the plan output, you can apply that file at a later time, so you guarantee what runs.

Terminal window
# in the PR pipeline:
nschema plan --out migration.nplan
# upload migration.nplan as a build artifact, review it...
# in the deploy pipeline, after approval:
nschema apply --plan-file migration.nplan --auto-approve

A scheduled job can alert when the live database diverges from recorded state:

Terminal window
nschema drift --detailed-exitcode # 2 = drift detected

See Detecting drift.

Code Meaning
0 Success / no changes.
1 Error, or a declined apply/destroy.
2 Changes present, from --detailed-exitcode and fmt --check.
130 Cancelled (Ctrl-C).

See the full exit-code contract.