Developer commands
Use blueprint dev to manage local servers and blueprint app to run the interactive client. See local development.
The commands below belong to the product’s BlueprintServer command runner. It handles serving, generation, and installation—not local process supervision. For app-plus-server startup, individual server control, logs, and watch, see development profiles. Executable paths and target names are supplied by the consuming product.
Product executable
A product can expose its existing target registry through a small entrypoint:
import 'dart:io';
import 'package:vyuh_blueprint_server/vyuh_blueprint_server.dart';
import '../lib/targets.dart'; // Product-owned file exporting blueprintRegistry.
Future<void> main(List<String> args) async {
exitCode = await BlueprintServer.runRegistry(blueprintRegistry, args);
}blueprintRegistry is a BlueprintRegistry containing the product's BlueprintTarget instances. Each target supplies its Blueprint and executable bindings. This snippet wires an existing assembly; it does not create a database or authentication provider.
If the product saves this entrypoint as bin/blueprint.dart, use:
dart run bin/blueprint.dart --help
dart run bin/blueprint.dart <target> --help
dart run bin/blueprint.dart targets --json
dart run bin/blueprint.dart <target> doctor --json
dart run bin/blueprint.dart <target> serve --host 127.0.0.1 --port 8080Replace <target> with a name listed by registry help. Passing only a target defaults to serve. A single-target executable calling BlueprintServer(target: target).run(args) omits the target argument.
Host and port precedence is command flag, then HOST / PORT, then 0.0.0.0 / 8080. The endpoint path comes from the Blueprint declaration.
Generate and install
Append these arguments after the product executable and target:
| Arguments | Behavior |
|---|---|
emit --out <dir> --schema-dir <NN_product> | Write the product SQL tree under an empty <dir> |
conformance [--out <file>] [--stdout] | Write the Define/Execute/Prove conformance artifact |
install or install all | Invoke database installation, then seeding |
install sql | Invoke database installation only |
install seed | Invoke seeding only |
install runtime | Install runtime artifacts through the optional runtime binding |
emit writes the tree laid out as the Supabase folder: schemas/<NN_product>/10_engine/ (the target's schema contributions), 20_model/, 30_runtime/, 90_runtime_contract/, and seed/<product>/ (the target's seed contributions). Every file starts with -- GENERATED from <product> blueprint and stays under 1,000 lines. It exits 64 for a usage error or a <dir> that is a file or not empty, 65 when the Blueprint or a contribution is rejected (nothing is written then), and 73 when writing fails. Contributions may write only into schemas the model owns, the runtime schema, and the schemas an engine declares in ownedSchemas.
emit is the only generation path. An installing binding applies the same file set, schemas/ files then seed/ files, in emitted order.
Write the generated SQL into Supabase
The installed CLI cannot import product code, so blueprint db emit runs the product's own target command and places its output in the Supabase folder:
blueprint db emit # write the generated folders
blueprint db emit --check # compare only; exit 1 on any difference
blueprint db emit --product plant --profile blueprint.dev.jsonDeclare the product in the development profile: its target command and its SQL.
{
"databases": {
"plant": {
"command": ["dart", "run", "bin/blueprint.dart", "plant"],
"install": [
"supabase/schemas/plant/00_base/*.sql",
"supabase/seed/plant/reference/*.sql"
],
"provision": ["supabase/seed/plant/provision/*.sql"]
}
}
}install (schemas and reference seeds) and provision (per-tenant defaults) are ordered globs relative to the profile directory, expanded as supabase db reset expands sql_paths, each file once. provision requires install. A product that declares install must not also be installed from config.toml: sql_paths may list only its provision files, and any other file under schemas/<NN>_<product>/ or seed/<product>/ (or in its install list) that sql_paths selects is a configuration error (exit 64) naming the entries. blueprint db status and reset read the same lists (--profile, default blueprint.dev.json); reset replays the install list, then the provision list.
A product is declared only here. supabase/config.toml does not define one: if its sql_paths list the generated files of a product the profile does not declare, the command exits 64 and names the databases.<product>.install key to add. --product is required unless the profile declares exactly one product.
The profile key must be the Blueprint name. The target names seed/<product>/ and the -- GENERATED from <product> blueprint header after its Blueprint, so a target whose emitted headers or seed folder name another product stops the command with exit 65, naming both names.
The CLI runs the command in the profile directory with emit --out <tmp> --schema-dir <NN_product> appended, streams its output to stderr, and then:
- Checks that the product's profile
installlist selects every emitted file, expanded assupabase db resetexpandssql_paths. Uncovered files are listed and nothing is written. - Always manages the four canonical folders
schemas/<NN_product>/{10_engine,20_model,30_runtime,90_runtime_contract}/, whether or not the target emitted into them, and the files inseed/<product>/that start with-- GENERATED from <product> blueprint. A file or directory in a canonical folder without that header, or a header-less file at a path the target emits underseed/<product>/, is hand-owned; the command names it and changes nothing. Other files and directories inseed/<product>/are left alone. - Without
--check, writes missing and changed files, then removes generated files the target no longer emits, including a whole folder it stopped emitting and stale generated seed files. A canonical folder left empty is deleted. New files are written before anything is removed, so if writing fails (exit 73), running the command again completes it. - With
--check, writes nothing and listsmissing,extraandchangedpaths.
| Exit | Meaning |
|---|---|
| 0 | Written, or --check found no difference |
| 1 | --check found a difference |
| 64 | Usage, profile or config error (including a missing databases.<product> entry, sql_paths listing a file of a product that declares install, or sql_paths listing a product's generated files that the profile does not declare), or a hand-owned file in a generated location |
| 65 | An emitted file that the install list does not select, that is outside the generated locations or lacks the header, or that names another product |
| 69 | The target command could not be started |
| 70 | The target command exited non-zero; the message target command exited N gives its code |
| 73 | A file-system error while writing |
db emit needs no database.
conformance writes JSON to --out, or to the target's conformanceOutput (default build/blueprint/conformance.json); --stdout prints it instead. It exits 0 when the declaration is conformant and 65 when it is not; the artifact is written either way.
Installation changes the configured database and follows the product binding's semantics. It is not a universal migration command. install all and install sql accept --reset, which resets managed objects; use the product's forward migration procedure for existing data. A normal dev launcher must not silently reset data.
What is still product-specific
The server runner owns serve, emit, install, conformance, and structural target doctor checks. The separate CLI package owns dev, individual serve, targets, doctor, status, logs, stop, watch, and trusted local-template create. It delegates target execution and validation to the product registry.
Products still supply executable/provider bindings, health routes, database setup and migrations, and a development profile. The CLI does not provision identity or storage. See development profiles and the local development workflow.
Migrations
Database commands work on one target, printed first as Target: ... without its password: --database-url URI, else BLUEPRINT_DATABASE_URL (or the variable --database-env names), else the checkout's local Supabase database. The standalone migration snapshot|plan|check|apply|status and seed commands no longer exist; a product's migrations are the files below.
A product's migration files
A product whose profile entry databases.<product> declares install ships as migration files in supabase/migrations/, which Blueprint applies and records in its own ledger, blueprint_migrations.product_migrations, keyed by product and version. See product migrations for the model, the ledger, the state store, deployment and a worked example.
blueprint db migration new baseline --product plant # first: the baseline
blueprint db migration new add_notes --product plant # later: a delta
blueprint db migration new --check --product plant # local: exit 1 when one is needed
blueprint db reset --allow-reset [--from-tree] [--force] # replay migrations, then provision
blueprint db migration up --product plant [--dry-run] # apply the pending files
blueprint db migration up --product plant --allow-remote # deploy: BLUEPRINT_DATABASE_URL
blueprint db migration adopt --product plant # once: move rows out of Supabase's historyup applies each pending file in one transaction with its ledger row, prints the target as host:port/database (never the URI), and runs no provision SQL. Deploy these files with up, not supabase db push, which records them in the Supabase CLI's own history instead of the ledger.
| Flag | Command | Effect |
|---|---|---|
--allow-destructive | migration new | Consent to every removal, and allow destructive operations on objects no definition derives |
--decisions FILE | migration new | Answers for changes that need one (renames, conversions, label maps, redirects, removals) |
--accept-renames[=old->new,...] | migration new | Accept every detected rename, or only the listed ones |
--acknowledge-unplanned | migration new | Record unplanned statements you migrated by hand |
--check | migration new | Write nothing; exit 1 when a migration is needed (local database only) |
--force | migration new, reset | Drop or capture even while other schemas depend on the product |
--from-tree | reset | Install the product's files and record no migration in the ledger |
--dry-run | migration up, migration adopt | List what would be applied or moved; change nothing |
--allow-remote | migration up, migration adopt, install, reset | Allow a host that is not a loopback address |
--allow-out-of-order | migration up | Apply pending files older than the newest applied one |
--include-retired | migration adopt | Also move the product's rows that have no migration file here |
--database-env NAME | every database command | Database URI variable (default BLUEPRINT_DATABASE_URL, else the local Supabase database) |
--database-url URI | every database command but migration up and adopt | The database; wins over the variable |
migration new exits 0 (written, no changes, --check clean), 1 (--check found drift), 64, 65 (review needed or capture refused), 69, 70 (the product command failed, or wrote no definition or migration steps) or 73. migration up exits 0 (applied, up to date, dry run), 1 (a file failed, or the database reported another error), 64, 65 (refused with nothing changed, or a schema is missing after the files were applied) or 69 (unreachable, a failed connection, or a lock held elsewhere for 10 seconds). migration adopt exits 0, 1 (the database reported an error), 64, 65 (a row of the product has no migration file here; see --include-retired) or 69.
Supported changes and limitations
The PostgreSQL migration engine supports ordinary tables, columns, defaults, nullability, constraints, indexes, views, functions, triggers, policies, sequences, and object and column grants. Some objects are rebuilt inside the transaction, so rehearsal should also measure locking and runtime against production-sized data.
Identity columns, partitioned tables, materialized views, domains, and default privileges are blocked. Changes to enum labels require a staged replacement and are currently blocked too. Cross-schema renames, automatic lifecycle state mappings, and arbitrary function dependency changes are not complete. Do not use this as an unattended production upgrader.