
Security News
New Study Identifies 53 Slopsquatting Targets Across 5 Frontier LLMs
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.
@prisma-next/cli
Advanced tools
> **For the CLI command, install [`prisma-next`](https://www.npmjs.com/package/prisma-next).** > The public `prisma-next` package ships the `prisma-next` binary and nothing > else — it has no library exports. > > This package (`@prisma-next/cli`) is both
For the CLI command, install
prisma-next. The publicprisma-nextpackage ships theprisma-nextbinary and nothing else — it has no library exports.This package (
@prisma-next/cli) is both the CLI's implementation and the documented programmatic-API import target. Authors of build integrations, extension packs, and advanced config wiring import from@prisma-next/cli/config-types,@prisma-next/cli/control-api,@prisma-next/cli/commands/*, and@prisma-next/config-loader. These subpaths are less stable than the facade packages (@prisma-next/postgres/config,@prisma-next/mongo/config); prefer those for application-level config.This README is architecture and internal documentation for contributors; the user-facing README lives in the
prisma-nextpackage.
Command-line interface for Prisma Next contract emission and management.
The CLI provides commands for emitting canonical contract.json and contract.d.ts files from TypeScript-authored contracts. It enforces import allowlists and validates contract purity to ensure deterministic, reproducible artifacts. Generated files include metadata and warning headers to indicate they're generated artifacts and should not be edited manually.
Provide a command-line interface that:
contract.json, contract.d.ts)prisma-next.config.ts files using Arktype validationdist/cli.mjs and also writes a compatibility shim at dist/cli.jsThe CLI performs wiring validation at the composition boundary: it ensures the emitted contract artifacts are compatible with the descriptors wired in prisma-next.config.ts.
This prevents runtime mismatches (for example: a contract that declares extension packs, but a config that doesn’t provide the matching descriptors).
Commands that enforce wiring validation:
db verifydb signdb initdb updateIf you hit a wiring validation error: add the required descriptors to config.extensionPacks (matched by descriptor id) and re-run the command.
Note: Control plane domain actions (database verification, contract emission) are implemented in @prisma-next/emitter and @prisma-next/framework-components/control. The CLI uses the control plane domain actions programmatically but does not define control plane types itself.
Commands use separate short and long descriptions via setCommandDescriptions():
See src/utils/command-helpers.ts for setCommandDescriptions() and getLongDescription().
prisma-next contract emit (canonical)Emit contract.json and contract.d.ts from config.contract.
Canonical command:
prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Config File Requirements:
The contract emit command does not require a driver in the config since it doesn't connect to a database:
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { contract } from './prisma/contract';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
extensionPacks: [],
contract: typescriptContract(contract, 'src/prisma/contract.json'),
});
Options:
--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Use config defaults
prisma-next contract emit
# JSON output
prisma-next contract emit --json
# Verbose output
prisma-next contract emit -v
prisma-next db verifyVerify that a database instance matches the emitted contract by checking the marker first and, by default, the live schema second.
Command:
prisma-next db verify [--db <url>] [--config <path>] [--marker-only | --schema-only] [--strict] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection if set)--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--marker-only: Skip schema verification and only check the database marker--schema-only: Skip marker verification and only check whether the live schema satisfies the contract--strict: When schema verification runs, schema elements not present in the contract are considered an error--marker-only cannot be combined with --schema-only or --strict (exit code 2, PN-CLI-4012). --schema-only --strict is valid.--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Use config defaults
prisma-next db verify
# Specify database URL
prisma-next db verify --db postgresql://user:pass@localhost/db
# Marker-only verification when callers accept the trade-off
prisma-next db verify --db postgresql://user:pass@localhost/db --marker-only
# Schema-only verification without relying on marker state
prisma-next db verify --db postgresql://user:pass@localhost/db --schema-only
# Strict schema verification (extras fail)
prisma-next db verify --db postgresql://user:pass@localhost/db --strict
# JSON output
prisma-next db verify --json
# Verbose output
prisma-next db verify -v
Config File Requirements:
The db verify command requires a driver in the config to connect to the database:
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgresDriver from '@prisma-next/driver-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { contract } from './prisma/contract';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
driver: postgresDriver,
extensionPacks: [],
contract: typescriptContract(contract, 'src/prisma/contract.json'),
db: {
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
},
});
Verification Process:
contract.json from config.contract.outputconfig.driver.create(url) to create a driverControlStack via createControlStack() and passes it to config.family.create(stack) to create a family instancefamilyInstance.verify() which:
PN-RUN-3001 if marker is missingPN-RUN-3003 if contract target doesn't match config targetPN-RUN-3002 if storageHash doesn't matchPN-RUN-3002 if profileHash doesn't match (when present)--marker-only is provided, calls familyInstance.schemaVerify() to catch schema mismatches such as missing tables or columns after manual DDL. By default this runs in tolerant mode; --strict treats schema elements not present in the contract as an error.--schema-only skips marker verification entirely and runs only schemaVerify(). This is useful for brownfield adoption and corrupt-marker diagnosis.Output Format (TTY):
Success:
✔ Database marker and schema match contract
verification: marker + schema
storageHash: sha256:abc123...
profileHash: sha256:def456...
Marker-only success:
✔ Database marker matches contract
verification: marker only (--marker-only)
storageHash: sha256:abc123...
profileHash: sha256:def456...
⚠ Schema verification skipped because --marker-only was provided
Marker failure:
✖ Marker missing (PN-RUN-3001)
Why: Contract marker not found in database
Fix: Run `prisma-next db sign --db <url>` to create marker
Schema drift failure:
db verify prints the schema verification tree / JSON payload and exits with code 1.
Output Format (JSON):
{
"ok": true,
"summary": "Database marker and schema match contract",
"mode": "full",
"contract": {
"storageHash": "sha256:abc123...",
"profileHash": "sha256:def456..."
},
"marker": {
"storageHash": "sha256:abc123...",
"profileHash": "sha256:def456..."
},
"target": {
"expected": "postgres"
},
"missingCodecs": [],
"schema": {
"summary": "Database schema satisfies contract",
"counts": {
"pass": 12,
"warn": 0,
"fail": 0,
"totalNodes": 12
},
"strict": false
},
"meta": {
"configPath": "/path/to/prisma-next.config.ts",
"contractPath": "/path/to/src/prisma/contract.json",
"schemaVerification": "performed"
},
"timings": {
"total": 42
}
}
Error Codes:
PN-CLI-4010: Missing driver in config — provide a driver descriptorPN-RUN-3001: Marker missing - Contract marker not found in databasePN-RUN-3002: Hash mismatch - Contract hash does not match database markerPN-RUN-3003: Target mismatch - Contract target does not match config target--schema-only)Family Requirements:
The family must provide a create() method in the family descriptor that accepts a ControlStack and returns a ControlFamilyInstance with a verify() method:
interface ControlFamilyDescriptor<TFamilyId, TFamilyInstance> {
create<TTargetId extends string>(
stack: ControlStack<TFamilyId, TTargetId>,
): TFamilyInstance;
}
interface ControlStack<TFamilyId, TTargetId> {
readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
readonly driver: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;
readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];
}
interface ControlFamilyInstance {
verify(options: {
driver: ControlDriverInstance;
contract: Contract;
expectedTargetId: string;
contractPath: string;
configPath?: string;
}): Promise<VerifyDatabaseResult>;
}
Use createControlStack() from @prisma-next/framework-components/control to create the stack with sensible defaults (driver defaults to undefined, extensionPacks defaults to []).
The SQL family provides this via @prisma-next/family-sql/control. The verify() method handles marker checks, full db verify follows it with schemaVerify(), --marker-only skips that schema step, and --schema-only runs schemaVerify() without marker checks.
prisma-next db schemaInspect the live database schema and display it as a human-readable tree or machine-consumable JSON. This command is read-only and never writes files.
Command:
prisma-next db schema [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection if set)--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Use config defaults
prisma-next db schema
# Specify database URL
prisma-next db schema --db postgresql://user:pass@localhost/db
# JSON output
prisma-next db schema --json
# Verbose output
prisma-next db schema -v
prisma-next contract inferInspect the live database schema and write an inferred PSL contract to disk. Use this for brownfield adoption when you want a starting contract.prisma before running contract emit and db sign.
Command:
prisma-next contract infer [--db <url>] [--config <path>] [--output <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection if set)--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--output <path>: Write the inferred PSL contract to the specified path--json: Output a JSON result envelope (includes psl.path)-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Infer contract.prisma next to the configured contract.json output
prisma-next contract infer
# Specify database URL
prisma-next contract infer --db postgresql://user:pass@localhost/db
# Override the output path
prisma-next contract infer --output ./prisma/contract.prisma
# JSON output
prisma-next contract infer --json
By default, contract infer writes to:
--output <path>, if providedcontract.prisma next to config.contract.outputcontract.prisma in the current working directoryConfig File Requirements:
Both db schema and contract infer require a driver in the config to connect to the database:
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgresDriver from '@prisma-next/driver-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
driver: postgresDriver,
extensionPacks: [],
db: {
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
},
});
Introspection Process:
config.driver.create(url) to create a driverControlStack via createControlStack() and passes it to config.family.create(stack) to create a family instancefamilyInstance.introspect() which:
SqlSchemaIR for SQL family)familyInstance.toSchemaView() to project the schema IR into a CoreSchemaView for displayOutput Format (TTY):
Human-readable schema tree:
sql schema (tables: 2)
├─ table user
│ ├─ id: int4 (not null)
│ ├─ email: text (not null)
│ └─ unique user_email_key
├─ table post
│ ├─ id: int4 (not null)
│ ├─ title: text (not null)
│ └─ userId: int4 (not null)
├─ extension plpgsql
└─ extension vector
Output Format (JSON):
{
"ok": true,
"summary": "Schema introspected successfully",
"schema": {
"root": {
"kind": "root",
"id": "sql-schema",
"label": "sql schema (tables: 2)",
"children": [
{
"kind": "entity",
"id": "table-user",
"label": "table user",
"children": [
{
"kind": "field",
"id": "column-user-id",
"label": "id: int4 (not null)",
"meta": {
"nativeType": "int4",
"nullable": false
}
}
]
}
]
}
},
"meta": {
"configPath": "/path/to/prisma-next.config.ts",
"dbUrl": "postgresql://user:pass@localhost/db"
},
"timings": {
"total": 42
}
}
Error Codes:
PN-CLI-4010: Missing driver in config — provide a driver descriptorPN-CLI-4005: Missing database connection — provide --db <url> or set db.connection in configFamily Requirements:
The family must provide:
create() method in the family descriptor that returns a ControlFamilyInstance with an introspect() methodtoSchemaView() method on the ControlFamilyInstance to project family-specific schema IR into CoreSchemaViewinterface ControlFamilyInstance {
introspect(options: {
driver: ControlDriverInstance;
contract?: Contract;
schema?: string;
}): Promise<FamilySchemaIR>;
toSchemaView?(schema: FamilySchemaIR): CoreSchemaView;
}
The SQL family provides this via @prisma-next/family-sql/control. The introspect() method queries the database catalog and returns SqlSchemaIR, and toSchemaView() projects it into a CoreSchemaView for display.
Note: The introspection output displays native database types (e.g., int4, text, timestamptz) rather than mapped codec IDs (e.g., pg/int4@1). This reflects the actual database state, which may be enriched with type mappings later.
prisma-next db signMark the database as matching the emitted contract by writing or updating the contract marker. This command verifies that the database schema satisfies the contract before signing, ensuring the marker is only written when the database is fully aligned.
Command:
prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection if set)--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Use config defaults
prisma-next db sign
# Specify database URL
prisma-next db sign --db postgresql://user:pass@localhost/db
# JSON output
prisma-next db sign --json
# Verbose output
prisma-next db sign -v
Config File Requirements:
The db sign command requires a driver in the config to connect to the database and a contract.output path to locate the emitted contract:
import { defineConfig } from '@prisma-next/cli/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgresDriver from '@prisma-next/driver-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { contract } from './prisma/contract';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
driver: postgresDriver,
extensionPacks: [],
contract: typescriptContract(contract, 'src/prisma/contract.json'),
db: {
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
},
});
Signing Process:
contract.json from config.contract.outputconfig.driver.create(url) to create a driverControlStack via createControlStack() and passes it to config.family.create(stack) to create a family instancefamilyInstance.schemaVerify() to verify the database schema matches the contract:
familyInstance.sign() which:
Output Format (TTY):
Success (new marker):
✔ Database signed (marker created)
storageHash: sha256:abc123...
profileHash: sha256:def456...
Total time: 42ms
Success (updated marker):
✔ Database signed (marker updated from sha256:old-hash)
storageHash: sha256:abc123...
profileHash: sha256:def456...
previous storageHash: sha256:old-hash
Total time: 42ms
Success (already up-to-date):
✔ Database already signed with this contract
storageHash: sha256:abc123...
profileHash: sha256:def456...
Total time: 42ms
Failure (schema mismatch):
✖ Schema verification failed
[Schema verification tree output]
Output Format (JSON):
{
"ok": true,
"summary": "Database signed (marker created)",
"contract": {
"storageHash": "sha256:abc123...",
"profileHash": "sha256:def456..."
},
"target": {
"expected": "postgres",
"actual": "postgres"
},
"marker": {
"created": true,
"updated": false
},
"meta": {
"configPath": "/path/to/prisma-next.config.ts",
"contractPath": "/path/to/src/prisma/contract.json"
},
"timings": {
"total": 42
}
}
For updated markers:
{
"ok": true,
"summary": "Database signed (marker updated from sha256:old-hash)",
"contract": {
"storageHash": "sha256:abc123...",
"profileHash": "sha256:def456..."
},
"target": {
"expected": "postgres",
"actual": "postgres"
},
"marker": {
"created": false,
"updated": true,
"previous": {
"storageHash": "sha256:old-hash",
"profileHash": "sha256:old-profile-hash"
}
},
"meta": {
"configPath": "/path/to/prisma-next.config.ts",
"contractPath": "/path/to/src/prisma/contract.json"
},
"timings": {
"total": 42
}
}
Error Codes:
PN-CLI-4010: Missing driver in config — provide a driver descriptorPN-CLI-4005: Missing database connection — provide --db <url> or set db.connection in configRelationship to Other Commands:
db verify: db verify checks that the marker exists and matches the contract, then runs schema verification by default. db sign writes the marker that db verify checks. Use db verify --marker-only for marker-only verification and db verify --schema-only to inspect only the live schema.Idempotency:
The db sign command is idempotent and safe to run multiple times:
Family Requirements:
The family must provide a create() method in the family descriptor that returns a ControlFamilyInstance with schemaVerify() and sign() methods:
interface ControlFamilyInstance {
schemaVerify(options: {
driver: ControlDriverInstance;
contract: Contract;
strict: boolean;
contractPath: string;
configPath?: string;
}): Promise<VerifyDatabaseSchemaResult>;
sign(options: {
driver: ControlDriverInstance;
contract: Contract;
contractPath: string;
configPath?: string;
}): Promise<SignDatabaseResult>;
}
The SQL family provides this via @prisma-next/family-sql/control. The sign() method handles ensuring the marker schema/table exist, reading existing markers, comparing hashes, and writing/updating markers internally.
prisma-next db initInitialize a database schema from the contract. This command plans and applies additive-only operations (create missing tables/columns/constraints/indexes) until the database satisfies the contract, then writes the contract marker.
Command:
prisma-next db init [--db <url>] [--config <path>] [--dry-run] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection if set)--config <path>: Optional. Path to prisma-next.config.ts (defaults to ./prisma-next.config.ts if present)--dry-run: Only show the migration plan, do not apply it--json [format]: Output as JSON (object only; ndjson is not supported for this command)-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)-vv, --trace: Trace output (deep internals, stack traces)--color/--no-color: Force/disable color outputExamples:
# Initialize database with config defaults
prisma-next db init
# Preview migration plan without applying
prisma-next db init --dry-run
# Specify database URL
prisma-next db init --db postgresql://user:pass@localhost/db
# JSON output
prisma-next db init --json
Config File Requirements:
The db init command requires a driver in the config to connect to the database:
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgresDriver from '@prisma-next/driver-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { contract } from './prisma/contract';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
driver: postgresDriver,
extensionPacks: [],
contract: typescriptContract(contract, 'src/prisma/contract.json'),
db: {
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
},
});
Initialization Process:
contract.json from config.contract.outputconfig.driver.create(url) to create a driverControlStack via createControlStack() and passes it to config.family.create(stack) to create a family instancefamilyInstance.introspect() to get the current database schema IRcontract.targetFamily matches config.family.familyIdcontract.target matches config.target.targetIdcontract.extensionPacks (if present) are provided by config.extensionPacks (matched by descriptor id)config.target.migrations.createPlanner() and config.target.migrations.createRunner()planner.plan() with the contract, schema IR, additive-only policy, and frameworkComponents (the active target/adapter/extension descriptors)
--dry-run):
runner.execute() to apply the planOutput Format (TTY - Plan Mode):
prisma-next db init ➜ Bootstrap a database to match the current contract
config: prisma-next.config.ts
contract: src/prisma/contract.json
mode: plan (dry run)
✔ Planned 4 operation(s)
│
├─ Create table user [additive]
├─ Add unique constraint user_email_key on user [additive]
├─ Create index user_email_idx on user [additive]
└─ Add foreign key post_userId_fkey on post [additive]
Destination hash: sha256:abc123...
This is a dry run. No changes were applied.
Run without --dry-run to apply changes.
Output Format (TTY - Apply Mode):
prisma-next db init ➜ Bootstrap a database to match the current contract
config: prisma-next.config.ts
contract: src/prisma/contract.json
Applying migration plan and verifying schema...
→ Create table user...
→ Add unique constraint user_email_key on user...
→ Create index user_email_idx on user...
→ Add foreign key post_userId_fkey on post...
✔ Applied 4 operation(s)
Marker written: sha256:abc123...
Output Format (JSON):
{
"ok": true,
"mode": "apply",
"plan": {
"targetId": "postgres",
"destination": {
"storageHash": "sha256:abc123..."
},
"operations": [
{
"id": "table.user",
"label": "Create table user",
"operationClass": "additive"
}
]
},
"execution": {
"operationsPlanned": 4,
"operationsExecuted": 4
},
"marker": {
"storageHash": "sha256:abc123..."
}
}
Error Codes:
PN-CLI-4004: Contract file not foundPN-CLI-4005: Missing database URLPN-CLI-4008: Unsupported JSON format (--json ndjson is rejected for db init)PN-CLI-4010: Missing driver in configPN-CLI-4020: Migration planning failed (conflicts)PN-CLI-4021: Target does not support migrationsPN-RUN-3000: Runtime error (includes marker mismatch failures)Behavior Notes:
db init succeeds as a noop (0 operations planned/executed).db init fails (including in --dry-run mode). Use db init for bootstrapping; use your migration workflow to reconcile existing databases.prisma-next db updateUpdate your database schema to match the currently emitted contract.
db update differs from db init:
db init (creates the signature table if missing)additive, widening, and destructive operation classes where supported by planner/runner--dry-run mode for SQL targets, prints a DDL preview derived from planned operations-y, --yes is providedCommand:
prisma-next db update [--db <url>] [--config <path>] [--dry-run] [-y|--yes] [--interactive|--no-interactive] [--json] [-v] [-q] [--color/--no-color]
Error codes (additional to shared CLI/runtime codes):
RUNNER_FAILED: runner rejected apply (origin mismatch, failed checks, policy failures, or execution errors)Config File (prisma-next.config.ts):
The CLI uses a config file to specify the target family, target, adapter, extensionPacks, and contract.
Config Discovery:
--config <path>: Explicit path (relative or absolute)./prisma-next.config.ts in current working directoryNote: The CLI uses c12 for config loading, but constrains it to the current working directory (no upward search) to match the style guide's discovery precedence.
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgres from '@prisma-next/target-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { contract } from './prisma/contract';
export default defineConfig({
family: sql,
target: postgres,
adapter: postgresAdapter,
extensionPacks: [],
contract: typescriptContract(contract, 'src/prisma/contract.json'),
});
Prefer helper utilities for authoring mode selection:
typescriptContract(contract, outputPath?) from @prisma-next/sql-contract-ts/config-types for TS-authored contractsprismaContract(schemaPath, { output?, target? }) from @prisma-next/sql-contract-psl/provider for PSL-authored providersThe contract.output field specifies the path to contract.json. This is the canonical location where other CLI commands can find the contract JSON artifact. Defaults to 'src/prisma/contract.json' if not specified.
contract.d.ts is always colocated with contract.json and derived from contract.output (contract.json → contract.d.ts).
Output:
contract.json: Includes _generated metadata field indicating it's a generated artifact (excluded from canonicalization/hashing)contract.d.ts: Includes warning header comments indicating it's a generated fileprisma-next migration planPlan a migration from contract changes. Compares a starting contract against a destination contract and produces a new migration package with the required operations. No database connection is needed — fully offline.
prisma-next migration plan [--config <path>] [--name <slug>] [--from <contract>] [--to <contract>] [--json] [-v] [-q] [--color/--no-color]
Options:
--config <path>: Path to prisma-next.config.ts--name <slug>: Name slug for the migration directory (default: migration)--from <contract>: Starting contract reference (hash, prefix, ref name, migration directory, <dir>^, or filesystem path). Defaults to the db ref (greenfield when absent).--to <contract>: Destination contract reference (same grammar as --from). Defaults to the emitted contract.json. Use --to <migration-dir>^ to plan a rollback toward a predecessor state.--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)What it does:
--to <contract> if provided, otherwise contract.jsonconfig.migrations.dir (default: migrations/)--from <contract> if provided, otherwise the db ref (greenfield when absent)migration.ts (containing placeholder(...) lambdas for any data transforms), migration.json (with a content-addressed migrationHash over the planned ops, or over [] when the planner could not lower any calls because of placeholders), ops.json (the planned ops, or [] in the placeholder-blocked case), and contract bookends. The package is always fully attested — there is no draft state on disk.placeholder(...) slots, the command returns a successful pendingPlaceholders envelope (a warning, not a failure) asking the developer to fill in the slots before re-emitting. The on-disk ops.json is [] and migrationHash is the hash of (metadata, []), so applying the migration as-written will not advance the storage hash to the intended destination — the runner's destination-hash post-check surfaces this as a state mismatch. After filling in the placeholders, run node migrations/<dir>/migration.ts to re-emit ops.json and the corresponding migrationHash. PN-MIG-2001 is raised only at self-emit time when a slot is still unfilled.Outputs:
migrations/<dir>/migration.ts — editable migration source (with placeholder(...) slots when the planner inserted them)migrations/<dir>/migration.json — fully attested metadata (migrationHash: string, never null)migrations/<dir>/ops.json — planned operations (empty list [] if placeholders blocked the planner)migrations/<dir>/start-contract.{json,d.ts} — bookend from the "from" side (when applicable)migrations/<dir>/end-contract.{json,d.ts} — bookend from the "to" sideBranching with --from and --to: Use --from to create a migration edge from a specific contract hash instead of the default starting point. Use --to to plan toward any resolved contract — including a rollback via <migration-dir>^ — instead of the emitted contract. This enables branched migration graphs and arbitrary-target (including reverse) edges without editing contract source.
prisma-next migration showDisplay a migration package's operations, DDL preview, and metadata. Accepts a directory path, a hash prefix (git-style matching against migrationHash), or defaults to the latest migration.
prisma-next migration show [target] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
[target]: Migration directory path or migrationHash prefix (defaults to latest)--config <path>: Path to prisma-next.config.ts--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose outputWhat it does:
target is a path (contains / or \), reads that directory directlytarget is a hash prefix, scans all attested migrations and matches against migrationHashDestructive warnings: When a migration contains destructive operations (e.g., DROP TABLE, ALTER COLUMN TYPE), the output includes a prominent ⚠ warning about potential data loss.
prisma-next migration statusShow the migration graph and applied status. Adapts based on context:
--ref: Targets a specific ref instead of the contract hash; all refs from refs.json are rendered on the graphprisma-next migration status [--db <url>] [--ref <name>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (enables online mode)--ref <name>: Target a named ref from migrations/refs.json instead of the current contract hash--config <path>: Path to prisma-next.config.ts--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose outputWhat it does:
migrations/refs.json (if present) and renders them on the graph--ref is provided, uses the ref's hash as the target instead of the contract hash; the active ref is highlighted in bold, other refs are dimmed◄ DB, ◄ Contract, and ◄ ref:<name> markers--ref mode, the CONTRACT.AHEAD warning is suppressed — contract being ahead of a ref target is expected in multi-environment workflowsBranched graphs: When the migration graph has multiple branches (divergence), status reports an AMBIGUOUS_TARGET error with the divergence point and branch details. Use --ref to target a specific branch.
prisma-next migrateApply planned migrations to the database. Executes previously planned migrations (created by migration plan). Compares the database marker against the migration graph to determine which migrations are pending, then executes them sequentially. Each migration runs in its own transaction. Does not plan new migrations — run migration plan first.
prisma-next migrate [--db <url>] [--to <contract>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
Options:
--db <url>: Database connection string (optional; defaults to config.db.connection)--to <contract>: Target contract reference (hash, prefix, ref name, migration directory, <dir>^, or filesystem path). When omitted, applies toward the emitted contract.json. When --to resolves to an on-disk graph node, verification and apply use that bundle's end-contract.json — so a planned rollback or other arbitrary-target edge applies without editing contract source.--ref <name>: Target a named ref from migrations/refs.json instead of the current contract hash--config <path>: Path to prisma-next.config.ts--json: Output as JSON object-q, --quiet: Quiet mode (errors only)-v, --verbose: Verbose output (debug info, timings)What it does:
config.migrations.dir. Every package is attested — there is no on-disk draft state. The loader (readMigrationPackage in @prisma-next/migration-tools/io) rehashes (metadata, ops) for each MigrationPackage it returns and confirms the result matches the stored migrationHash. If a package has been hand-edited or partially written since emit, the load fails with MIGRATION.HASH_MISMATCH pointing at the offending directory and asks the developer to re-run node migrations/<dir>/migration.ts (or restore from version control).--to / --ref, or from contract.json when neither is suppliedMigrationRunnerRollback workflow: When no on-disk edge reaches the target (for example migrate --to <migration-dir>^), the command refuses with MIGRATION.PATH_UNREACHABLE and suggests planning the missing edge with migration plan --from <current> --to <target> --name <slug>, then re-running migrate --to <target>. No contract-source edit is required.
Config requirements: Requires driver and db.connection (or --db). migrations.dir is optional and defaults to migrations/.
Resume semantics: If a migration fails, previously applied migrations are preserved. Re-running migrate resumes from the last successful migration.
Ref-based routing: With --ref, apply targets the ref's hash instead of the contract hash. This enables multi-environment workflows where staging and production track different points in the migration graph.
ops.json and computing migrationHashThere is no dedicated CLI command for emitting a migration — migrations
self-emit. After scaffolding (via migration plan or migration new),
run migration.ts directly with Node to produce ops.json and attest
migration.json:
node migrations/<dir>/migration.ts
The scaffolded migration.ts calls MigrationCLI.run(import.meta.url, ...) from @prisma-next/cli/migration-cli when invoked as the entrypoint. (Postgres and SQLite scaffolds re-export MigrationCLI through @prisma-next/postgres/migration or @prisma-next/sqlite/migration so a migration.ts only needs the single facade import; Mongo scaffolds still pull from @prisma-next/cli/migration-cli directly.) The CLI entrypoint loads prisma-next.config.ts, assembles a ControlStack, instantiates the migration with that stack (so dataTransform and other adapter-aware helpers can materialize a real adapter), and serializes operations to ops.json while writing the content-addressed migrationHash into migration.json. If migration.ts contains unfilled placeholder() slots, the script exits with PN-MIG-2001 and reports the slot to fill in.
MigrationCLI.run accepts an optional third argument { argv?, stdout?, stderr? } for in-process testability (default: process.argv / process.stdout / process.stderr) and returns the exit code as a Promise<number>. The flag surface is --help / --dry-run / --config <path>, parsed by clipanion. The main multi-command surface (prisma-next contract emit, db verify, etc.) uses Commander; the per-migration MigrationCLI.run entrypoint uses clipanion to keep authored migration files lightweight and in-process testable.
prisma-next migration refManage named refs in migrations/refs.json. Refs map logical environment names (e.g., staging, production) to contract hashes, enabling multi-environment migration workflows where different environments track different points in the migration graph.
prisma-next ref set <name> <contract> # Set a ref to a contract (hash, ref, dir, ...)
prisma-next ref list # List all refs (use `ref list` and filter for one ref)
prisma-next ref delete <name> # Delete a ref
Options (all subcommands):
--config <path>: Path to prisma-next.config.ts--json: Output as JSON object-q, --quiet: Quiet mode (errors only)Ref naming rules: Lowercase alphanumeric with hyphens or forward slashes (e.g., staging, prod/us-east). No . or .. segments.
Ref values: Must be valid contract hashes (sha256:<64 hex chars> or sha256:empty).
Atomic writes: refs.json is written atomically via temp file + rename to prevent corruption from concurrent writes.
flowchart TD
CLI[CLI Entry Point]
CMD_EMIT[Emit Command]
CMD_DB[DB Commands]
CMD_MIG[Migration Commands]
EXEC_EMIT[executeContractEmit]
PUBLISH[publishContractArtifactPair]
EMIT[Emitter]
CTRL[Control Client]
MIG_TOOLS["@prisma-next/migration-tools"]
FS[File System]
VITE["@prisma-next/vite-plugin-contract-emit"]
CLI --> CMD_EMIT
CLI --> CMD_DB
CLI --> CMD_MIG
CMD_EMIT --> EXEC_EMIT
VITE --> EXEC_EMIT
EXEC_EMIT --> EMIT
EXEC_EMIT --> PUBLISH
PUBLISH --> FS
CMD_DB --> CTRL
CMD_MIG --> CTRL
CMD_MIG --> MIG_TOOLS
MIG_TOOLS --> FS
CTRL --> FS
For agents/contributors:
executeContractEmitis the SINGLE publication path forcontract.json+contract.d.ts. The CLI command (prisma-next contract emit) and the Vite plugin (@prisma-next/vite-plugin-contract-emit) both call into it. Do NOT re-implement the load → emit → publish dance in a new caller; if you need additional behavior, extendContractEmitOptions/ContractEmitResultand updateexecuteContractEmititself.
How it composes:
queueEmitByOutput
(src/utils/emit-queue.ts). Concurrent calls for the same output line up
FIFO; concurrent calls for distinct outputs run in parallel. Last submission
wins on disk.publishContractArtifactPair
(src/utils/publish-contract-artifact-pair.ts) stages temp files, renames
contract.d.ts before contract.json, and attempts to restore the previous
pair if either rename fails — so type-only consumers never observe a
mismatched pair.disposeEmitQueue
on shutdown to drop the per-output queue state, otherwise the module-global
queue map leaks one entry per unique output path.The validateContractDeps warning is returned in ContractEmitResult.validationWarning
rather than written to stderr by the operation — callers (CLI, Vite plugin) decide
how to render it (ui.warn, plugin logger, etc.).
The defineConfig() function validates and normalizes configs using Arktype:
contract.output defaults to 'src/prisma/contract.json')See .cursor/rules/config-validation-and-normalization.mdc for detailed patterns.
cli.ts)--help, --version)exitOverride() to catch unhandled errors (non-structured errors that fail fast) and print stack traces. Commands handle structured errors themselves via process.exit().contract emit)configureHelp() to customize help output with styled format matching normal command output. Root help shows "prisma-next" title with command tree; command help shows "prisma-next ➜ " with options and docs URLs. See utils/formatters/help.ts for help formatters.setCommandDescriptions() usage.commands/contract-emit.ts)CliStructuredError), Result pattern, and process.exit(). Commands return Result<T, CliStructuredError>, process results with handleResult(), and call process.exit(exitCode) directly. See .cursor/rules/cli-error-handling.mdc for details.prisma-next.config.ts)config.contract.source.load(context) — context.resolvedInputs carries the absolute paths the CLI loader resolved from source.inputs — and expects Result<Contract, ContractSourceDiagnostics>config.contract is missingconfig.contract.output (already normalized by defineConfig() with defaults applied)config.family.create() (assembles operation registry, type imports, extension IDs)familyInstance.emitContract() with raw contract (instance handles stripping mappings and validation internally)api/emit-contract.ts)emitContract(options): Programmatic API for emitting contracts
utils/errors.ts, utils/cli-errors.ts, utils/result.ts, utils/result-handler.ts)CliStructuredError instances with full context (why, fix, docsUrl, etc.)Result<T, CliStructuredError> and use handleResult() for output and exit codesCliStructuredError.toEnvelope() converts errors to envelopes for output formattinghandleResult() processes Results, formats output, and returns exit codesexitOverride() with stack traces.cursor/rules/cli-error-handling.mdc for detailed patternsconfig.family.create() and reads assembly data (operation registry, type imports, extension IDs) from the instance.pack-assembly.ts has been removed. Pack assembly is now handled by family instances. For SQL family, tests can import pack-based helpers directly from packages/2-sql/3-tooling/family/src/core/assembly.ts using relative paths.createSqlFamilyInstance in @prisma-next/family-sql).utils/formatters/)relative(process.cwd(), path))formatStyledHeader() creates styled headers for command output with "prisma-next ➜ " format
config:, contract:)formatRootHelp() - Formats root help with "prisma-next" title, command tree, and multiline descriptionformatCommandHelp() - Formats command help with "prisma-next ➜ ", options, subcommands, docs URLs, and multiline descriptionrenderCommandTree() - Shared function to render hierarchical command trees with tree characters (├─, └─, │)wrap-ansi for ANSI-aware wrappingdefault: <value> on the following line (dimmed)string-width and strip-ansi to measure and pad text correctly with ANSI codesconfigureHelp() in cli.ts to apply to all commandscreate(options) - Creates a family instance that implements domain actionshook - Target family hook for contract emissiondeserializeContract(contractJson) - Validates and normalizes contract, returns Contract without mappingsemitContract(options) - Emits contract (handles stripping mappings and validation internally)verify(options) - Verifies database marker against contractschemaVerify(options) - Verifies database schema against contractintrospect(options) - Introspects database schemaversion: Component version included in emitted metadata (useful for debugging and reproducibility).capabilities: Feature flags the component contributes (e.g., adapter/runtime lowering requirements). Typically namespaced by target (e.g., { postgres: { returning: true } }) so contracts can be validated against the active target.types: Type import specs and type IDs contributed by the component. Common examples:
types.codecTypes.import: Where to import codec type mappings for contract.d.ts.types.queryOperationTypes.import: Where to import flat query-builder operation type signatures for contract.d.ts (adapters/extensions).types.storage: Storage type bindings (typeId, nativeType, etc.) used in authoring/emission.operations: Operation signatures the component contributes (extensions), used for type generation and (optionally) validation/lowering.contractSpace (used by verify, planning, and migration flows and not required at runtime).Unlike the older manifest-based IR approach (separate JSON manifests + a parsing/validation step to build an IR), descriptors are imported directly from packages (e.g., @prisma-next/*/control). This removes a file-format boundary and keeps the data and its types co-located.
Illustrative example (descriptor object):
import type { SqlControlExtensionDescriptor } from '@prisma-next/family-sql/control';
const exampleExtension: SqlControlExtensionDescriptor<'postgres'> = {
kind: 'extension',
id: 'example',
version: '1.0.0',
familyId: 'sql',
targetId: 'postgres',
capabilities: { postgres: { 'example/feature': true } },
types: {
queryOperationTypes: {
import: {
package: '@prisma-next/extension-example/operation-types',
named: 'QueryOperationTypes',
alias: 'ExampleQueryOperationTypes',
},
},
},
operations: [],
create: () => ({ familyId: 'sql', targetId: 'postgres' }),
};
export default exampleExtension;
How CLI consumers import/use it:
defineConfig() (see “Config File Requirements” under prisma-next contract emit above; also see “Entrypoints” below for the @prisma-next/*/control subpaths):import { defineConfig } from '@prisma-next/cli/config-types';
import exampleExtension from '@prisma-next/extension-example/control';
export default defineConfig({
// family/target/adapter/driver omitted for brevity
extensionPacks: [exampleExtension],
});
commander: CLI argument parsing and command routingesbuild: Bundling TypeScript contract files with import allowlisting@prisma-next/emitter: Contract emission engine (returns strings)@prisma-next/migration-tools: On-disk migration I/O, hash verification, and history reconstruction@prisma-next/framework-components: Control plane types, migration operation types, control stack (via ./control)@prisma-next/errors: Error types and factories (via ./control)@prisma-next/* packages allowed (MVP). Expand later if needed.commander library for robust CLI argument parsing._generated metadata field to contract.json to indicate it's a generated artifact. This field is excluded from canonicalization/hashing to ensure determinism. The contract.d.ts file includes warning header comments generated by the emitter hook.The CLI package includes unit tests, integration tests, and e2e tests:
E2E tests use a shared fixture app pattern to ensure proper module resolution:
test/cli-e2e-test-app/ contains a static package.json with dependenciesfixtures/emit/, fixtures/db-verify/)package.json at the rootsetupTestDirectoryFromFixtures() handles directory setup and returns a cleanup functionafterEach hooks or finally blocks)Example:
import { setupTestDirectoryFromFixtures } from './utils/test-helpers';
const fixtureSubdir = 'emit';
it('test description', async () => {
const testSetup = setupTestDirectoryFromFixtures(
fixtureSubdir,
'prisma-next.config.emit.ts',
);
const cleanupDir = testSetup.cleanup;
try {
// ... test code ...
} finally {
cleanupDir(); // Each test cleans up its own directory
}
});
See .cursor/rules/cli-e2e-test-patterns.mdc for detailed patterns and examples.
Run tests:
pnpm test # Run all tests
pnpm test:unit # Run unit tests only
pnpm test:integration # Run integration tests only
pnpm test:e2e # Run e2e tests only
The CLI package provides a programmatic control client for running control-plane operations without using the command line. This is useful for:
import { createControlClient } from '@prisma-next/cli/control-api';
import sql from '@prisma-next/family-sql/control';
import postgres from '@prisma-next/target-postgres/control';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import postgresDriver from '@prisma-next/driver-postgres/control';
// Create a control client with framework component descriptors
const client = createControlClient({
family: sql,
target: postgres,
adapter: postgresAdapter,
driver: postgresDriver,
extensionPacks: [],
});
try {
// Connect to database
await client.connect(databaseUrl);
// Run operations
const verifyResult = await client.verify({ contract });
const initResult = await client.dbInit({ contract, mode: 'apply' });
const updateResult = await client.dbUpdate({ contract, mode: 'apply' });
const introspectResult = await client.introspect();
} finally {
// Clean up
await client.close();
}
| Method | Description |
|---|---|
connect(url) | Establishes database connection |
close() | Closes connection (idempotent) |
readMarker() | Reads contract marker from database (null if none) |
verify(options) | Verifies database marker matches contract |
schemaVerify(options) | Verifies database schema satisfies contract |
sign(options) | Writes contract marker to database |
dbInit(options) | Initializes database schema from contract |
dbUpdate(options) | Updates database schema to match contract |
migrate(options) | Advances the database to the target contract via the migration graph |
introspect(options) | Introspects database schema |
Operations return structured result types:
readMarker() → ContractMarkerRecord | nullverify() → VerifyDatabaseResultschemaVerify() → VerifyDatabaseSchemaResultsign() → SignDatabaseResultdbInit() → Result<DbInitSuccess, DbInitFailure> (uses Result pattern)dbUpdate() → Result<DbUpdateSuccess, DbUpdateFailure> (uses Result pattern)migrate() → Result<MigrateSuccess, MigrateFailure> (uses Result pattern)introspect() → Schema IR (family-specific)connect()connect()| Aspect | CLI | Control API |
|---|---|---|
| Config | Reads prisma-next.config.ts | Accepts descriptors directly |
| File I/O | Reads contract.json from disk | Accepts contract directly |
| Output | Formats for console | Returns structured data |
| Exit codes | Uses process.exit() | Returns results/throws |
The CLI package exports several subpaths for different use cases:
@prisma-next/cli (main export): Exports loadContractFromTs and createContractEmitCommand@prisma-next/cli/config-types: Exports defineConfig and config types@prisma-next/cli/control-api: Exports createControlClient and control API types@prisma-next/cli/commands/db-init: Exports createDbInitCommand@prisma-next/cli/commands/db-update: Exports createDbUpdateCommand@prisma-next/cli/commands/db-schema: Exports createDbSchemaCommand@prisma-next/cli/commands/db-sign: Exports createDbSignCommand@prisma-next/cli/commands/db-verify: Exports createDbVerifyCommand@prisma-next/cli/commands/contract-emit: Exports createContractEmitCommand@prisma-next/cli/commands/contract-infer: Exports createContractInferCommand@prisma-next/cli/commands/migration-plan: Exports createMigrationPlanCommand@prisma-next/cli/commands/migration-show: Exports createMigrationShowCommand@prisma-next/cli/commands/migration-status: Exports createMigrationStatusCommand@prisma-next/cli/commands/migrate: Exports createMigrateCommand@prisma-next/config-loader: Exports loadConfigImportant: loadContractFromTs is exported from the main package (@prisma-next/cli). See .cursor/rules/cli-package-exports.mdc for import patterns.
This package is part of the framework domain, tooling layer, migration plane:
packages/1-framework/3-tooling/cli@prisma-next/emitter - Contract emission enginedocs/briefs/complete/20-CLI-Support-for-Extension-Packs.mdFAQs
> **For the CLI command, install [`prisma-next`](https://www.npmjs.com/package/prisma-next).** > The public `prisma-next` package ships the `prisma-next` binary and nothing > else — it has no library exports. > > This package (`@prisma-next/cli`) is both
The npm package @prisma-next/cli receives a total of 18,147 weekly downloads. As such, @prisma-next/cli popularity was classified as popular.
We found that @prisma-next/cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.

Security News
The White House’s Gold Eagle Initiative aims to coordinate AI-discovered vulnerabilities, validate findings, and accelerate patching across critical software.

Security News
A Shai-Hulud infection exposed Suno's source code, which shows the AI music startup stream-ripped tracks to train its models.