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.
Always pass --auto-approve for applies
Section titled “Always pass --auto-approve for applies”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:
nschema apply --auto-approveSupply secrets through the environment
Section titled “Supply secrets through the environment”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:
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"Plugins are restored on first use
Section titled “Plugins are restored on first use”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/BACKENDblocks. - To control when the fetch happens: fail fast on a bad pin, or warm the cache before timed steps. Run
nschema initup front, and pass--no-initto later commands to require the cache and skip any restore.
Gate a pull request on changes
Section titled “Gate a pull request on changes”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:
nschema plan --detailed-exitcode # 0 = no changes, 2 = changes, 1 = errorIf a state store is configured, this will run without a database connection. See Offline planning & state.
Enforce formatting
Section titled “Enforce formatting”Fail the build if any .sql file isn’t canonically formatted:
nschema fmt --check # exits 2 if files need formatting, 1 on errorValidate schema files fast
Section titled “Validate schema files fast”A quick, database-free correctness check, checks syntax and some basic structural checks like missing references or empty tables:
nschema validatePlan now, apply later
Section titled “Plan now, apply later”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.
# 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-approveMonitor for drift on a schedule
Section titled “Monitor for drift on a schedule”A scheduled job can alert when the live database diverges from recorded state:
nschema drift --detailed-exitcode # 2 = drift detectedSee Detecting drift.
Exit codes, summarized
Section titled “Exit codes, summarized”| 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.