Deployment scripts
Some setup can’t be expressed declaratively — creating an extension, a role, a custom grant, or backfilling data. For these, NSchema has deployment scripts: raw SQL that runs before or after the computed migration.
Declaring them inline: PRE/POST DEPLOYMENT
Section titled “Declaring them inline: PRE/POST DEPLOYMENT”Deployment scripts are declared inline in your .sql files, with a dollar-quoted body:
PRE DEPLOYMENT 'enable_citext' AS $$ CREATE EXTENSION IF NOT EXISTS citext;$$;
POST DEPLOYMENT 'reindex' (run_outside_transaction = true) AS $$ CREATE INDEX CONCURRENTLY idx_widgets_name ON app.widgets (name);$$;PRE DEPLOYMENTblocks run before the computed migration;POST DEPLOYMENTblocks run after it.
The name (a single-quoted string) appears in plan output and logs. The body is opaque SQL —
NSchema runs it verbatim rather than parsing it as declarative schema. They sit right alongside
your table and view declarations in the same files; plan previews them
and apply runs them.
The run_outside_transaction = true option is for statements the database forbids inside a
transaction (e.g. CREATE INDEX CONCURRENTLY). See the
grammar reference for the full syntax.
This is the same whether you drive NSchema through the CLI or by embedding the engine — scripts live in the DDL either way.
They must be idempotent
Section titled “They must be idempotent”When to use them
Section titled “When to use them”Reach for a deployment script only for what NSchema’s declarative model doesn’t cover: extensions, roles, data backfills, concurrent index builds, and similar imperative steps. Everything NSchema does model — tables, columns, constraints, indexes, views, and so on — belongs in the declarative schema, so the planner can diff it.