Skip to content

All versions since 4.0.0

4.0.0

Version 4.0.0 changes the provider and backend model to function as plugins resolved through the NuGet package manager.

Added

  • Third-party providers and backends. A PROVIDER / BACKEND block can name any plugin package with a source attribute.
  • nschema init now restores plugins. init now pre-fetches the provider and backend plugins pinned in your config. Operations restore implicitly on first use; init just does it up front so the first real command is fast.
  • --no-init flag. Skips the implicit plugin restore and requires the plugins to be cached already.
  • lock command group. nschema lock status / lock acquire / lock release inspect, manually hold, and release the state lock. lock acquire holds a lock that outlives the command (for out-of-band checks before a migration), with an optional --ttl (e.g. 30m) and --reason, lock status surfaces any information about the currently held lock. lock release requires the lock id by default (refusing if it no longer matches the held lock), with --force to release whatever lock is held without naming it.
  • --no-lock flag on apply, refresh, and destroy. Runs without taking the state lock.
  • nschema state show <file> renders a state file on disk directly, without a configured backend.
  • nschema db show renders the live database schema, read directly from the database via the provider — the online counterpart to state show.
  • plugin command group. nschema plugin list shows the provider and backend plugins your project pins and whether each is restored; plugin show
  • --format option (text | json | markdown), selecting the output format for any command. --json is now shorthand for --format json.
  • Markdown output. --format markdown renders the plan, SQL, and schema as Markdown for a PR comment or a CI job summary.

Changed

  • Providers and backends are now plugins. They ship as separate NuGet packages instead of being bundled with the tool; nschema restores the one pinned in your config on first use (it shells out to the .NET SDK to do so). The local-file state backend remains built in.
  • Scaffolding moved from init to nschema scaffold. Creating a starter project is now nschema scaffold (init became the restore command above). Its PROVIDER / BACKEND config blocks and the sample schema are rendered by the plugins themselves.
  • PROVIDER / BACKEND blocks now require a pinned version (the plugin package version); the built-in file backend is the exception. A first-party label (postgres, sqlite, sqlserver, s3) still resolves to its package automatically.
  • A PROVIDER block is now required to select a provider. NSCHEMA_POSTGRES_CONNECTION_STRING and the other connection-string variables no longer name the provider on their own — they still override the connection string set in the block.
  • doctor reports plugin problems as diagnostics. A provider or backend that fails to restore or configure is now reported by doctor as a health-check finding (every such problem at once) instead of aborting on the first.
  • Lock commands grouped under lock. lock-statusnschema lock status; force-unlocknschema lock release, whose prompt is now skipped with --auto-approve/-y (consistent with apply/destroy) instead of --force. The lock-id safety check is unchanged.
  • show split by what it shows. The recorded state is now nschema state show (offline; the state noun group will grow pull/push/move), and a saved plan is nschema plan show <file>. The top-level show command is gone.
  • completion install / completion uninstall subcommands replace the --install-autocomplete / --uninstall-autocomplete flags. nschema completion <shell> still prints the script.
  • Built on NSchema.Core 4.0.0 and the 4.0 provider/backend packages.

Fixed

  • Running nschema --help in a busy directory like root would cause a performance slowdown due to the --environment arg autocomplete recursively scanning all the files in the directory. This has been fixed by removing autocomplete.
  • Torn reads of the local state file. The built-in file state store now writes to a temporary sibling file and atomically renames it into place, so a command reading the recorded state while another run writes it.

Removed

  • The NSCHEMA config block. destructive_action moved to the --destructive-actions flag / the NSCHEMA_DESTRUCTIVE_ACTION_POLICY environment variable; dialect and transaction_mode (never wired in) are gone. An NSCHEMA block is now rejected as an unknown configuration block.
  • The top-level show, lock-status, and force-unlock commands, replaced by state show / plan show and the lock group above. The show --online live-schema view is now nschema db show (a db noun group) rather than a mode flag.

4.0.1

Fixed

  • Updated to NSchema.Core 4.0.1 which fixes several issues to do with action ordering when objects are renamed.

4.1.0

Added

  • Updated to NSchema.Core 4.1.0 which adds support for schema and table templates.

4.2.0

Added

  • Data-hazard detection. plan and apply (via NSchema.Core 4.2.0) now flag changes that are valid against the schema but can fail on the data already in a table.

4.3.0

Added

  • Data migrations. A MIGRATION ['name'] FOR <trigger> <schema>.<table>.<member> AS $$…$$; block (via NSchema.Core 4.3.0) attaches raw SQL to an ADD COLUMN, ALTER COLUMN TYPE, or ADD CONSTRAINT change and runs only when that change is in the plan. A required column add with a matching block is applied as add-nullable → backfill → SET NOT NULL, a matching block silences the corresponding data-hazard warning, and a block matching nothing is reported as safe to delete. The plan output gains a “Data migrations” section (dataMigrations in --json). Executing a plan with a matched block requires a provider plugin at 4.3 or later.

Changed

  • The import command now writes the per-schema header to <schema>/schema.sql instead of <schema>.sql.

Fixed

  • The nschema lock release command suggested by lock status and lock acquire now carries the --environment and --directory arguments of the current invocation.
  • The diff now shows an added or removed column’s default expression and identity marker.
  • DDL syntax errors now name the file the error was found in, alongside the existing line and column.
  • The import command no longer repeats the CREATE SCHEMA statement in every object file; only the per-schema header declares the schema.

4.4.0

Added

  • Unified SCRIPT statement (via NSchema.Core 4.4.0). SCRIPT '<name>' RUN [ALWAYS | ONCE] ON <event> AS $$…$$; is the new canonical form of deployment scripts and data migrations: the event is PRE DEPLOYMENT, POST DEPLOYMENT, or a structural change (ADD COLUMN / ALTER COLUMN TYPE / ADD CONSTRAINT with a target path).
  • Run-once scripts. A RUN ONCE script is recorded in the state backend on a successful apply and skipped by later plans; a recorded script whose body has since changed stays skipped and warns. Plan output marks run-once scripts in the pre/post-deployment sections ((run once); runCondition in --json). Recording requires a state backend — planning without one warns.
  • Scripts in schema templates. Both script kinds can be declared inside a TEMPLATE … BEGIN … END; body and instantiate once per applied schema, with the {schema} token substituted in the name and the SQL.

Changed

  • Script names must be unique across the project (they identify scripts in diagnostics and run-once tracking); a template-declared script applied to multiple schemas can include {schema} in its name.

Deprecated

  • The PRE|POST DEPLOYMENT '<name>' AS $$…$$; and MIGRATION ['name'] FOR <trigger> <path> AS $$…$$; forms still work, but plan/apply/validate now surface a deprecations warning naming the SCRIPT replacement. They will be removed in NSchema 5.0.

4.5.0

Added

  • refresh --force refresh fails if it finds an unreadable state payload, instead of silently overwriting it; --force replaces it, resetting the script ledger.
  • state pull [file] to pull the raw recorded state payload out of the configured backend. Writes to a file or stdout.
  • state push <file> to push the raw recorded state payload into the configured backend. Push takes the state lock (--no-lock to skip).
  • script command group to manage the scripts recorded in the state:
    • script list shows the recorded scripts (name, execution time, body hash); --json emits them as a single array.
    • script hash [name] computes the body hash of the project’s script declarations, bare on stdout for one script, or a listing of all of them, for hand-editing pulled state.
    • script taint <name> removes a script’s record, so it runs again on the next apply.
    • script untaint <name> records a script as executed without running it, using the body hash from the script’s declaration. Taint and untaint take the state lock (--no-lock to skip).

4.5.1 Latest

Changed

  • A RUN ONCE script that has already been run no-longer produces an informational diagnostic.