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/BACKENDblock can name any plugin package with asourceattribute. nschema initnow restores plugins.initnow pre-fetches the provider and backend plugins pinned in your config. Operations restore implicitly on first use;initjust does it up front so the first real command is fast.--no-initflag. Skips the implicit plugin restore and requires the plugins to be cached already.lockcommand group.nschema lock status/lock acquire/lock releaseinspect, manually hold, and release the state lock.lock acquireholds a lock that outlives the command (for out-of-band checks before a migration), with an optional--ttl(e.g.30m) and--reason,lock statussurfaces any information about the currently held lock.lock releaserequires the lock id by default (refusing if it no longer matches the held lock), with--forceto release whatever lock is held without naming it.--no-lockflag onapply,refresh, anddestroy. Runs without taking the state lock.nschema state show <file>renders a state file on disk directly, without a configured backend.nschema db showrenders the live database schema, read directly from the database via the provider — the online counterpart tostate show.plugincommand group.nschema plugin listshows the provider and backend plugins your project pins and whether each is restored; plugin show--formatoption (text|json|markdown), selecting the output format for any command.--jsonis now shorthand for--format json.- Markdown output.
--format markdownrenders 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;
nschemarestores 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
inittonschema scaffold. Creating a starter project is nownschema scaffold(initbecame the restore command above). ItsPROVIDER/BACKENDconfig blocks and the sample schema are rendered by the plugins themselves. PROVIDER/BACKENDblocks now require a pinnedversion(the plugin package version); the built-infilebackend is the exception. A first-party label (postgres,sqlite,sqlserver,s3) still resolves to its package automatically.- A
PROVIDERblock is now required to select a provider.NSCHEMA_POSTGRES_CONNECTION_STRINGand the other connection-string variables no longer name the provider on their own — they still override the connection string set in the block. doctorreports plugin problems as diagnostics. A provider or backend that fails to restore or configure is now reported bydoctoras a health-check finding (every such problem at once) instead of aborting on the first.- Lock commands grouped under
lock.lock-status→nschema lock status;force-unlock→nschema lock release, whose prompt is now skipped with--auto-approve/-y(consistent withapply/destroy) instead of--force. The lock-id safety check is unchanged. showsplit by what it shows. The recorded state is nownschema state show(offline; thestatenoun group will growpull/push/move), and a saved plan isnschema plan show <file>. The top-levelshowcommand is gone.completion install/completion uninstallsubcommands replace the--install-autocomplete/--uninstall-autocompleteflags.nschema completion <shell>still prints the script.- Built on
NSchema.Core 4.0.0and the 4.0 provider/backend packages.
Fixed
- Running
nschema --helpin a busy directory like root would cause a performance slowdown due to the--environmentarg 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
NSCHEMAconfig block.destructive_actionmoved to the--destructive-actionsflag / theNSCHEMA_DESTRUCTIVE_ACTION_POLICYenvironment variable;dialectandtransaction_mode(never wired in) are gone. AnNSCHEMAblock is now rejected as an unknown configuration block. - The top-level
show,lock-status, andforce-unlockcommands, replaced bystate show/plan showand thelockgroup above. Theshow --onlinelive-schema view is nownschema db show(adbnoun group) rather than a mode flag.
4.0.1
Fixed
- Updated to
NSchema.Core 4.0.1which fixes several issues to do with action ordering when objects are renamed.
4.1.0
Added
- Updated to
NSchema.Core 4.1.0which adds support for schema and table templates.
4.2.0
Added
- Data-hazard detection.
planandapply(viaNSchema.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 (viaNSchema.Core 4.3.0) attaches raw SQL to anADD COLUMN,ALTER COLUMN TYPE, orADD CONSTRAINTchange 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 (dataMigrationsin--json). Executing a plan with a matched block requires a provider plugin at 4.3 or later.
Changed
- The
importcommand now writes the per-schema header to<schema>/schema.sqlinstead of<schema>.sql.
Fixed
- The
nschema lock releasecommand suggested bylock statusandlock acquirenow carries the--environmentand--directoryarguments 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
importcommand no longer repeats theCREATE SCHEMAstatement in every object file; only the per-schema header declares the schema.
4.4.0
Added
- Unified
SCRIPTstatement (viaNSchema.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 isPRE DEPLOYMENT,POST DEPLOYMENT, or a structural change (ADD COLUMN/ALTER COLUMN TYPE/ADD CONSTRAINTwith a target path). - Run-once scripts. A
RUN ONCEscript 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);runConditionin--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 $$…$$;andMIGRATION ['name'] FOR <trigger> <path> AS $$…$$;forms still work, but plan/apply/validate now surface adeprecationswarning naming theSCRIPTreplacement. They will be removed in NSchema 5.0.
4.5.0
Added
refresh --forcerefresh fails if it finds an unreadable state payload, instead of silently overwriting it;--forcereplaces 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-lockto skip).scriptcommand group to manage the scripts recorded in the state:script listshows the recorded scripts (name, execution time, body hash);--jsonemits 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-lockto skip).
4.5.1 Latest
Changed
- A
RUN ONCEscript that has already been run no-longer produces an informational diagnostic.