Skip to main content
The supaschema.config.json file is the single source of truth for how supaschema discovers your schema files, generates migrations, connects to databases, and enforces safety rules. Place it in your project root alongside package.json, and supaschema will pick it up automatically every time you run a command.

Config File Discovery

supaschema resolves its configuration in the following order:
  1. --config <path> CLI flag — explicitly point to any config file at an arbitrary path; this always takes precedence and skips auto-discovery entirely
  2. supaschema.config.json — standard JSON config in the project root
  3. supaschema.config.mjs — ESM module that exports a config object as its default export, tried after .json
  4. supaschema.config.js — CJS or ESM module, tried after .mjs
  5. Built-in defaults — if no config file is found, all options fall back to their default values
When you use a .mjs or .js config, export your config object as the default export:
// supaschema.config.mjs
export default {
  adapter: "supabase-auto",
  schemaPaths: ["supabase/schemas"],
  migrationsDir: "supabase/migrations",
  destructiveChanges: "hint-required",
};
Add the $schema property to your supaschema.config.json to get full autocomplete and inline documentation in VS Code and other editors that support JSON Schema.

Complete Example

{
  "$schema": "./node_modules/supaschema/config-schema.json",
  "adapter": "supabase-auto",
  "destructiveChanges": "hint-required",
  "schemaPaths": ["supabase/schemas"],
  "migrationsDir": "supabase/migrations",
  "typesFile": "src/database.types.ts",
  "transactionMode": "per-migration",
  "excludedGrantRoles": [
    "supabase_admin",
    "supabase_auth_admin",
    "supabase_storage_admin"
  ]
}

Option Reference

$schema

$schema
string
A URL or local path pointing to the supaschema JSON Schema file. Setting this enables editor autocomplete and validation for all config options. Use "./node_modules/supaschema/config-schema.json" for a local project installation.

adapter

adapter
"supabase-auto" | "postgres"
default:"\"supabase-auto\""
Controls which schema adapter supaschema uses when diffing your schema files against a live database.
  • supabase-auto — automatically excludes Supabase-managed schemas (auth, storage, realtime, etc.) from declarative ownership and blocks accidental changes to them.
  • postgres — plain PostgreSQL mode with no special-cased schemas. Use this for non-Supabase Postgres deployments.

cascade

cascade
"never"
default:"\"never\""
Cascade mode for destructive operations. This is always "never" and cannot be changed — it is a safety invariant that ensures supaschema never silently cascades drops to dependent objects.
cascade is fixed at "never". Any attempt to set another value will cause a validation error at startup.

destructiveChanges

destructiveChanges
"hint-required" | "block" | "allow"
default:"\"hint-required\""
Governs how supaschema responds when the computed diff contains a destructive operation such as a column drop, a type change, or a table removal.
  • hint-required — supaschema blocks the migration and emits a diagnostic code (SUPA_PLAN_DESTRUCTIVE_HINT_REQUIRED) unless you have added the relevant object key to hints.destructive. This is the recommended default.
  • block — supaschema unconditionally blocks all destructive operations. Use this in CI pipelines that should never allow data-loss changes.
  • allow — supaschema renders destructive SQL without requiring hints. Use only in non-production environments where data loss is acceptable.
Setting destructiveChanges to "allow" in a production config is strongly discouraged. A mis-typed column name or accidental schema deletion will silently produce a DROP COLUMN migration.

environments

environments
object
default:"{}"
A map of named environments, each containing a databaseUrl string. Named environments let you run supaschema commands against different database targets without repeating connection strings on the CLI. See the Environments guide for full details.
{
  "environments": {
    "local": {
      "databaseUrl": "postgresql://postgres:postgres@localhost:54322/postgres"
    },
    "staging": {
      "databaseUrl": "postgresql://user:pass@staging-host:5432/mydb"
    }
  }
}

excludedGrantRoles

excludedGrantRoles
string[]
default:"[]"
A list of role names that supaschema ignores when tracking GRANT and REVOKE statements. This prevents supaschema from generating spurious permission migrations for internal Supabase roles that are managed outside your schema files.
{
  "excludedGrantRoles": [
    "supabase_admin",
    "supabase_auth_admin",
    "supabase_storage_admin"
  ]
}

hints.destructive

hints.destructive
string[]
default:"[]"
An array of object key strings that explicitly approve destructive changes on specific database objects. When supaschema encounters a destructive operation whose key is present here, it renders a safe ALTER or DROP … IF EXISTS instead of blocking. See the Hints guide for key format details.

hints.renames

hints.renames
array
default:"[]"
An array of { from, to } pairs that tell supaschema a database object was renamed rather than dropped and recreated. Each value uses the same kind:schema.name object key format as hints.destructive. See the Hints guide for supported rename kinds and restrictions.

idempotency

idempotency
"required"
default:"\"required\""
Idempotency requirement for generated migrations. This is always "required" and cannot be changed — supaschema guarantees that every migration it emits can be safely re-applied without side effects.

lockTimeout

lockTimeout
string
default:"\"5s\""
The lock_timeout injected at the top of each migration statement. Accepts PostgreSQL interval notation: "5s", "500ms", "1min". Keeping this low prevents long-running migrations from holding locks that block application queries.

managedSchemas

managedSchemas
string[]
Schemas that supaschema treats as externally managed. Objects inside these schemas are excluded from declarative ownership and will never appear in the diff output. When using the supabase-auto adapter, this list is automatically populated with Supabase’s platform-owned schemas.
You can extend managedSchemas to exclude third-party schemas (for example, a timescaledb schema) from supaschema’s ownership model.

migrationsDir

migrationsDir
string
default:"\"supabase/migrations\""
The directory where supaschema writes generated migration .sql files. Filenames follow the YYYYMMDDHHmmss_<slug>.sql convention. The directory is created automatically if it does not exist.

normalize

normalize
"deparse" | "off"
default:"\"deparse\""
Controls SQL normalization applied to schema files before diffing.
  • deparse — parses SQL into an AST and deparses it back to canonical form, eliminating cosmetic differences between your schema file and the live database.
  • off — disables normalization. Use only when debugging unexpected diff output.

postgresVersion

postgresVersion
string
default:"\"15+\""
The target PostgreSQL version. supaschema uses this to gate version-specific SQL features (for example, MERGE statements, pg_catalog additions). Accepts semver-style strings: "14", "15", "15+", "16".

renameDetection

renameDetection
"hints-only" | "off"
default:"\"hints-only\""
Controls how supaschema detects object renames.
  • hints-only — renames are only recognized when you supply an explicit hints.renames entry. This avoids false-positive rename detection.
  • off — rename detection is fully disabled; drops and additions are always treated as independent operations.

schemaPaths

schemaPaths
string[]
default:"[\"supabase/schemas\"]"
One or more directories that supaschema scans for schema SQL files. Files are read in lexicographic order within each directory. You can supply multiple paths to compose schemas from separate locations.
{
  "schemaPaths": ["supabase/schemas", "packages/shared/schemas"]
}

schemas.include

schemas.include
string[]
default:"[]"
When non-empty, supaschema only diffs the schemas listed here. All other schemas in the database are ignored, even if they contain objects not present in your schema files.

schemas.exclude

schemas.exclude
string[]
default:"[]"
Schemas to skip entirely during diffing. Objects inside excluded schemas are never touched regardless of what is in your schema files.
schemas.include and schemas.exclude are mutually exclusive. Setting both produces a validation error.

statementTimeout

statementTimeout
string
default:"\"60s\""
The statement_timeout injected at the top of each migration statement. Accepts PostgreSQL interval notation. Raise this value for migrations that involve large table rewrites; keep it low in OLTP environments to avoid query starvation.

transactionMode

transactionMode
"per-migration" | "per-statement"
default:"\"per-migration\""
Controls how migration SQL is wrapped in transactions.
  • per-migration — wraps the entire migration file in a single BEGIN … COMMIT block. If any statement fails, the whole migration rolls back.
  • per-statement — each statement runs in its own transaction. Use this when your migration contains statements that cannot run inside a transaction (for example, CREATE INDEX CONCURRENTLY).

typesFile

typesFile
string
default:"\"database.types.ts\""
Output path for the generated TypeScript types file. supaschema writes a fully typed Database interface here that mirrors your schema. Pass this file to the Supabase client for end-to-end type safety.

zodFile

zodFile
string
default:"\"database.zod.ts\""
Output path for the generated Zod validators file. When set, supaschema emits Zod schemas for every table and view in your schema, ready to use for runtime validation.

validators

validators
string[]
default:"[\"internal-parser\"]"
An array of SQL validators that supaschema runs against your schema files before diffing. Available validators:
ValidatorDescription
internal-parsersupaschema’s built-in parser; always runs
squawkSquawk linter for migration safety rules
pglsPostgreSQL Language Server linting
sqlfluffSQLFluff style and syntax linter
pg-formatterpg_formatter style checker (runs pg-formatter --check)
Each additional validator must be installed separately and available on your PATH. A configured validator that is not installed produces a SUPA_VALIDATOR_UNAVAILABLE error — configured checks never silently skip.
{
  "validators": ["internal-parser", "squawk"]
}