Configuration
Project configuration lives in your project files, in SQL-statement-shaped blocks. They declare the engine version the project needs, the plugins it depends on, which database to connect to, and where to keep state.
nschema new puts these in a config.nsql.
The four statements
Section titled “The four statements”-- the engine version this project needsENGINE ( version = '[5.0,6.0)');
-- the plugins the project depends on, and the versions it pins them toPLUGIN postgres ( source = 'NSchema.Postgres', version = '[5.0,6.0)');
-- which database to connect to (the connection string is best supplied via the environment)DATABASE postgres ( connection_string = '', command_timeout = 30);
-- where to keep stateSTATE file ( path = './nschema.state.json');| Statement | Purpose |
|---|---|
ENGINE |
Asserts the engine (and optionally host-tool) version the project requires. |
PLUGIN <label> |
Declares a plugin dependency: a package and version, or a path to a build. |
DATABASE <label> |
The live database. See Databases. |
STATE <label> |
The state store. See State. |
ENGINE, DATABASE, and STATE may each appear at most once; PLUGIN may appear as often as you have plugins.
Plugins
Section titled “Plugins”Every plugin the project uses is declared explicitly by a PLUGIN statement, which pairs a label (your local name
for it) with the package it comes from:
PLUGIN pg ( source = 'NSchema.Postgres', version = '[5.0,6.0)');
PLUGIN s3 ( source = 'NSchema.Aws', version = '[5.0,6.0)');DATABASE and STATE then reference a label:
DATABASE pg ( connection_string = '' );
STATE s3 ( bucket = 'my-bucket', key = 'env/state.json');The label is just an identifier, and has no bearing on the plugin. The one exception is STATE file, the local-file
store built into the engine, which needs no matching PLUGIN.
A version is either an exact pin ('5.0.0') or a NuGet-style range ('[5.0,6.0)').
To see which plugins a project declares and whether each is restored, use plugin list;
the shared on-disk cache is inspected and pruned with the plugin cache commands.
Loading a plugin from a path
Section titled “Loading a plugin from a path”A plugin can name a built .NET assembly instead of a package, which skips the package resolution and the shared cache entirely:
PLUGIN pg ( path = './artifacts/NSchema.Postgres.dll');This is for working on a plugin, and for build pipelines that want to test what they have just built rather than what they last published. Relative paths resolve against the project root, not the working directory.
The assembly needs its dependency closure beside it, that is, a .deps.json and the packages it references, which is
what a provider project produces when it sets:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>Without it, only the plugin’s own assembly lands in bin and loading fails.
That is reported on every run as plugin-from-path, so a CI log shows when a run used a build rather than a release.
A project that loads one deliberately — a plugin’s own test harness, say — can silence it in .editorconfig:
[*]nschema_diagnostic.plugin-from-path.severity = noneThe lockfile
Section titled “The lockfile”While the declared range indicates the acceptable plugin versions, the actually resolved version is pinned in the lockfile.
nschema init resolves every declaration and records the result in nschema.lock, beside your configuration:
LOCK ( source = 'NSchema.Postgres', version = '5.0.0');- A range resolves to the highest available version it admits, and then pinned, so that every subsequent check resolves to the same version.
plugin update [<label>]re-resolves ranges and rewrites the lockfile;plugin outdatedshows what an update would change without doing it.
Check nschema.lock in to version control: it is what makes a plan reproducible across machines and CI.
A plugin declared by path never appears in the lockfile. There is no version to
record, and writing one in would claim a reproducibility the path cannot offer. For the same reason
plugin update and plugin outdated skip it: there
is no range to widen and no feed to ask.
The engine assertion
Section titled “The engine assertion”ENGINE states which engine a project is written against, so an incompatible tool fails immediately with a clear
message rather than mis-planning:
ENGINE ( version = '[5.0,6.0)', -- the engine (NSchema.Core) host_version = '[5.0,6.0)' -- the host tool (the nschema CLI));Both attributes are optional. new writes a version assertion pinned to the CLI’s current major.
Where configuration files live
Section titled “Where configuration files live”Configuration can live in any of the project files alongside your schema, but I’d recommend keeping them separate in a
well-known file. All of mine are stored in config.nsql. Environment files (files named *.env.<name>.nsql) are
only read when that environment is selected, so put environment-specific configuration in a file with the
.env.<name> marker.
Environments
Section titled “Environments”Select an environment with --environment <name> (or NSCHEMA_ENVIRONMENT) and every
*.env.<name> file is layered over the base:
nschema plan --environment prod # base + *.env.prod.nsqlnschema plan --environment staging # base + *.env.staging.nsqlnschema plan # base onlyConfiguration in an overlay
Section titled “Configuration in an overlay”An overlay merges with any configuration in the base files, overwriting any re-declared config keys:
-- config.nsqlSTATE s3 ( bucket = 'acme-state', key = 'nschema.state.json' );
-- config.env.prod.nsql — the bucket carries throughSTATE s3 ( key = 'prod/nschema.state.json' );Restating it under a different label replaces it outright instead, because a different label is a different plugin
and there is nothing meaningful to merge — that is how an overlay swaps the state store for another. PLUGIN
declarations from both layers carry through.
Schema in an overlay
Section titled “Schema in an overlay”Schema declarations can also appear in overlays, and add to the base project. It’s a relatively niche use case, but it can be useful for things like a set of test tables to run integration tests against:
-- fixtures.env.test.nsql — planned only under --environment testCREATE TABLE test.orders_fixture ( id INT NOT NULL);Precedence
Section titled “Precedence”Settings resolve from three layers, in increasing order of precedence:
- Configuration statements. The base values, plus any selected environment overlay.
- Environment variables.
NSCHEMA_*. - Command-line options. Per-run flags.
See also
Section titled “See also”- Environment variables. The full list of
NSCHEMA_*overrides. - Databases. The available database providers.
- State. The available state stores.
- Configuration statements. The grammar these statements parse under.