Skip to content

All versions since 4.5.1

4.5.1

Changed

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

5.0.0

v5.0 moves the CLI onto NSchema.Core 5.0, whose rearchitecture reshapes configuration, plugins, and planning. Changes below are relative to 4.5.1.

Added

  • --scope takes an object, not just a schema. A value is an address — --scope app for a whole schema, --scope app.orders for one object. Read under the NSQL identifier rules, so a quoted segment can carry dots and spaces (--scope '"my.schema"."Order Details"').
  • --ephemeral on plan, apply, and destroy runs against an in-memory state store discarded when the command exits, standing in for a configured STATE store — for CI pipelines that bootstrap disposable databases. Run-once script history does not persist across runs in this mode.
  • A lockfile (nschema.lock) pins declared plugin versions to concrete versions. init resolves each PLUGIN — a range to the highest available version, an exact pin to itself — and records it; later commands read the pin, so a plugin without a lockfile entry is an error that points to init.
  • plugin update [<label>] re-resolves ranges to their highest available version and rewrites the lockfile — every plugin, or a single one by label.
  • plugin outdated shows each plugin’s pinned version against the newest its range allows (what update would install) and the newest available for this engine.
  • new asks the plugins what it needs to know. A database or state plugin can declare the questions its configuration needs, composing the answers into the statement it writes.
  • --set <key>=<value> on new answers a question up front, so a scripted run never blocks. Repeatable.

Changed

  • Environments select configuration, not schema. --environment layers the environment’s files over the base configuration; schema files are no longer overlaid per environment. An overlay merges the DATABASE, STATE, or ENGINE statement attributes.
  • DATABASE and STATE replace PROVIDER and BACKEND. Each names the thing it configures. The built-in local-file store is STATE file ( path = '…' );.
  • PLUGIN declares plugin dependencies. PLUGIN <label> ( source = '…', version = '…' ); names the package and pins its version; DATABASE/STATE reference the label. The built-in label-to-package map is gone — every plugin is declared explicitly, and version/source no longer ride the configuring statement. A version may be an exact pin or a NuGet-style range ([5.0,6.0)).
  • ENGINE ( version = '…' ); asserts the engine version. A project can require an engine version range; a mismatch fails with a pointer to dotnet tool update.
  • new authors the ENGINE assertion. A scaffolded project pins the engine to the CLI’s current major (e.g. ENGINE ( version = '[5.0,6.0)' );), so it fails fast on an incompatible tool.
  • new runs init afterwards, resolving and locking the plugins it declared so the project is ready to plan immediately. Pass --no-init to skip it for an offline or edit-first workflow.
  • Planning always diffs recorded state against the project, so plan (and a fresh apply) now require both a database and a state store. Planning against the live database is no longer available; use refresh to capture the live schema first.
  • destroy reads the managed schema from the recorded state. The fallback to the working-directory schema when no store was configured is gone, and a state store is now required.
  • Plan output folds scripts into the diff. Deployment and change-event scripts are first-class parts of the diff, shown in the plan tree (and carried on the diff object in --json); the separate pre/post-deployment and data-migration sections are gone.
  • Policy-blocked plans still render. A plan blocked by policy shows the complete diff and SQL alongside the blocking diagnostics; error severity is what stops an apply.
  • --destructive-actions accepts Ignore alongside Error, Warn, and Allow.
  • Abbreviated commands are spelled out. fmt is format, db is database, and scaffold is new. The old names are gone rather than aliased, so a script still using one fails loudly instead of drifting.
  • apply re-runs policies. The policy flags now apply to apply --plan-file too, re-checking the saved plan before executing it.
  • script hash, script taint, and script untaint operate on deployment scripts. A template-scoped script is addressed as schema.name, as script hash lists it.
  • Errors you can fix are reported as diagnostics; anything else is considered a a bug. A broken configuration file, an unresolvable plugin, an unreachable database — each renders in the diagnostics table, sourced by the file and line or the plugin label that caused it. Anything else reaching the top level is a defect in NSchema: it names the exception type, links the issue tracker, and prints a stack trace unconditionally, so a report needs no re-run with a flag. Messages carry the inner-exception chain, so a cause like Failed to connect to 127.0.0.1:5432 -> Connection refused keeps the part that matters.
  • --json distinguishes the two. An expected failure emits a {"type":"diagnostics"} event; an internal error’s {"type":"error"} event gains exception and stack, so a consumer can tell “your project is wrong” from “NSchema is broken” by a null check.

Fixed

  • Editing a PLUGIN version now works correctly. init preferred the lockfile’s pin unconditionally, so changing a declared version and re-running init silently kept restoring the old one.
  • An incompatible plugin doesn’t crash the CLI. This CLI will now give a proper explanation of the problem instead.
  • plugin update exits non-zero when a restore fails, rather than reporting the problem and returning 0.
  • Plugin loading now resolves a plugin’s native libraries (e.g. SQLite’s e_sqlite3) from its restored dependency closure.
  • new names the right environment variable. It pointed at a per-provider variable (NSCHEMA_POSTGRES_CONNECTION_STRING) that no longer has any effect; it now names NSCHEMA_DATABASE_CONNECTION_STRING.
  • Contradictory flags fail fast. --quiet with --verbose, or --json with a non-json --format, are now rejected while parsing.
  • A failed command always exits non-zero. lock release, init, new, and the plugin commands reported failures but still exited 0.
  • state show reports an error when no state has been recorded yet instead of failing on a missing source.

5.0.1

Fixed

  • --destructive-actions argument is ignored. Policy enforcement overrides like --destructive-actions and --data-hazards weren’t being respected due to a bug in Core. This is fixed after updating to 5.0.1.

5.1.0

Changed

  • Implicit schemas are now ignored. Schemas owned by the database (dbo, public, main, etc.) will now be ignored during import and planning.

Fixed

  • Plugin dependencies are not shared correctly. All plugin dependencies will now be correctly loaded from their own dependency closure where the CLI does not have its own version of an assembly.

5.2.0

Changed

  • Plans verify type references. Inherited from NSchema.Core 5.2.0, a plan now checks that every type the project references will exist once it applies.

Fixed

  • Schema-qualified engine types no longer block planning. Applying an imported project that referenced engine types (e.g. Postgres’s pg_catalog.tsvector) previously failed with an error demanding a declaration nobody could write.

5.3.0

Changed

  • A create is a create. Built on NSchema.Core 5.3: a plan that believes it is creating a routine or view now renders a plain CREATE, so colliding with an object the plan didn’t know about fails loudly instead of being silently overwritten; the in-place forms render only when the plan knows it is replacing.

Fixed

  • Rebuilding a schema whose functions reference its tables. Routines are now created after the tables they may reference, so applying an imported schema with SQL-language functions (e.g. Pagila) no longer fails with a missing relation.

5.4.0

Added

  • Aggregate support. CREATE AGGREGATE is part of the language (inherited from NSchema.Core 5.4.0).
  • Plugin restore honors your project’s NuGet configuration. Plugin resolution and restore now run under the project directory, so a NuGet.Config beside the project applies as expected.

Fixed

  • Functions that call each other now apply in the right order. Inherited from NSchema.Core 5.4: a routine’s definition is scanned for the routines it calls and the objects it reads, and creates are ordered so a callee precedes its caller.
  • Plugin restore works inside a repository using central package management. Only your NuGet configuration reaches the restore now; a Directory.Packages.props (or Directory.Build.props) further up the tree no longer breaks it with NU1008.

5.5.0

Fixed

  • Engine-native SQL bodies no longer show as permanent drift. Inherited from NSchema.Core 5.5.0, hand-written and database-written provider-native SQL (things like view bodies or trigger definitions) are now stored in the state so they can be diffed like-for-like.

5.6.0

Changed

  • Full dependency graph support. Updated to NSchema.Core 5.6.0, which refactors the linearizer to be built entirely from the dependency graph.

Fixed

  • Imported SQL Server projects read back. Inherits NSchema.Core 5.5.1: multi-statement routine definitions and view bodies survive the import round trip via dollar-quoted bodies, and trailing line comments no longer swallow the closing tokens.

5.6.1

Fixed

  • Multi-line doc comments indent correctly. Every line of a --- doc comment on a column or setting now takes the member indent, rather than only the first.
  • A state payload with no captured schema is rejected. Reading one now fails as an unreadable payload, instead of throwing an NRE.
  • Lockfiles are updated additively. Pinning package version now no-longer clobbers packages that weren’t in the updated list, so initializing plugins for one environment won’t remove pins for a different environment.

5.7.0

Changed

  • apply and destroy capture the live schema before planning. Before the plan step of apply and destroy, the state is now refreshed. This helps capture drift and also bootstraps the state before a first apply, which is particularly helpful when using the ephemeral store. Replaying a saved plan with --plan-file is unaffected, since its statements were fixed when the plan was written.

5.7.1

Fixed

  • Environment overlays can declare schema again. Database objects declared in *.env.<name>.sql will now join the project alongside the base files, restoring the v4 behavior.

5.8.0

Changed

  • --quiet now summarizes the run’s output. A quiet plan or apply reports one line per artifact (Plan: 2 to add, 1 to change, 0 to destroy (5 statements).) instead of the full diff and SQL.
  • --quiet drops Info diagnostics. The run-once “already executed” advisories no longer repeat on every planned run.
  • --quiet suppresses the environment banner and secondary hint lines (such as lock acquire’s release hint), which previously printed regardless.

Fixed

  • --json no longer writes the confirmation prompt into the result stream. An interactive apply --json wrote its summary and question to stdout as raw markup, breaking nschema apply --json | jq; the prompt now renders on stderr with the rest of the narration. The same fix keeps a piped --format markdown job summary free of prompt text. Without a terminal, the summary is reported as a {"type":"log"} event so a redirected stderr stays uniform NDJSON.
  • --json reports a Detail line at its own log level. Secondary hint lines were emitted as "level":"announcement", indistinguishable from top-level narration.
  • format rejects the presentation flags instead of ignoring them. nschema format --json (and --format, --quiet, --verbose) because format’s output is the formatted code.
  • The NO_COLOR environment variable and --no-color args should now be respected correctly.

5.9.0

Added

Clustering and XML indexes. Added support for clustering, XML indexes and view indexes, all inherited from NSchema.Core 5.7.

5.10.0

Added

  • Plugins can be loaded from a path. A PLUGIN statement declaring path loads the assembly directly, skipping the package restore and the shared cache entirely.

5.11.0

Added

  • Diagnostic severities can be set in .editorconfig. nschema_diagnostic.<code>.severity configures one finding and nschema_diagnostic_source.<source>.severity every finding from a producer, taking Roslyn’s severity words (none, silent, suggestion, warning, error, default). A --destructive-actions flag still wins over the file.
  • The diagnostics table names each finding’s code, which is what a severity is configured by.

Fixed

  • import reports its diagnostics whether or not it succeeded. They were shown only on failure, so a successful import had no way to tell you what it could not carry into the project.

5.11.1

Added

  • plan --json names the action behind each statement. Every entry in sql carries the action it performs (CreateTable, AddForeignKey), so what a plan exercises can be read off it rather than inferred from the SQL text. Inherited from NSchema.Core.

Fixed

  • An unreadable .editorconfig no longer crashes init, new, plan show or completion install/uninstall.
  • plan show reports a corrupt plan file instead of crashing on it. Inherited from NSchema.Core: a well-formed JSON object that is not a plan deserialized into nulls, and showing it died with a NullReferenceException in the reporter rather than naming the file.
  • .editorconfig severities now reach the findings that reading a project produces, not only the engine’s.

5.11.2

Fixed

  • Migration plan file unable to be deserialized. An accidental breaking change was introduced in NSchema.Core 5.9.1 that now been fixed.

5.11.3

Fixed

  • Check constraints no longer cause permanent drift. Check constraints are engine-native SQL, so it gets reformatted by the database. We now store both sides of a check constraint and only compare like to like.

5.11.4

Fixed

  • Engines without comment support no-longer cause errors on comments. Engines that don’t support comments now correctly ignore them.

5.11.5

All inherited from the latest NSchema.Core update.

Fixed

  • Every remaining authored expression settles. Column defaults and generated expressions, index and exclusion predicates, and a domain’s checks and default are opaque SQL, rewritten by the engine, so a handwritten one would never match. All are now kept and declared like-for-like as they are for triggers, routines etc. An expression the database no longer reports is still drift, not a spelling to restore.
  • Renaming a type no longer retypes the columns declared against it. The rename moved the type but left every reference naming the old one, so each column read as a retype.
  • Recreate is now correctly blocked by dependents. Recreating a type that’s in use now causes an error.
  • An identity that explicitly declares no options no longer differs from one that does so implicitly. No options at all and a set of unstated ones now compare equal.
  • A sequence altered for one reason no longer restates the others. The change carries the folded options, so a plan that changes the cache does not also restate a start it never asked to change.
  • Identity and sequence restarts now warn correctly. Restarts are data hazards: restarting the counter, means duplicate values are issued, meaning inserts collide with what is already stored.

5.12.0 Latest

Added

  • NSQL extension. Project files can now be written as .nsql files, which can be syntax highlighted using NSchema.Core’s TextMate grammar.

Changed

  • Default extension. When scaffolding or importing project files, the default file extension is now .nsql