Skip to main content

Plan Command Limitations

The postkit db plan command uses pgschema to generate schema diffs. Understanding what pgschema supports (and doesn't) will help you use the plan command effectively.

How the Plan Command Works

┌─────────────────────────────────────────────────────────────────────────────┐
│ DB PLAN COMMAND WORKFLOW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ $ postkit db plan │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 1. Read schema │ │ 2. Combine all │ │
│ │ files │───────────►│ files into │ │
│ │ │ │ schema.sql │ │
│ └──────────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ 3. Run pgschema │ │
│ │ plan (diff) │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ 4. Compare with │ │
│ │ current DB │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ 5. Generate │ │
│ │ migration │ │
│ │ plan │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

What pgschema DOES Support

Schema-level objects within a schema are fully supported:

Object TypeSupported
TablesCREATE TABLE, ALTER TABLE
ViewsCREATE VIEW, CREATE MATERIALIZED VIEW
FunctionsCREATE FUNCTION
TriggersCREATE TRIGGER
IndexesCREATE INDEX, CREATE UNIQUE INDEX
ConstraintsPRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK
EnumsCREATE TYPE ... AS ENUM
DomainsCREATE DOMAIN
SequencesCREATE SEQUENCE

What pgschema DOES NOT Support

pgschema does not support cluster and database level commands:

Cluster Level (Not Supported)

CommandAlternative
CREATE DATABASEUse db/infra/ or manual migration
CREATE ROLEUse db/infra/ or manual migration
CREATE TABLESPACEUse manual migration
CREATE USERUse db/infra/ or manual migration

Database Level (Not Supported)

CommandAlternative
CREATE EXTENSIONUse db/infra/ or manual migration
CREATE SCHEMAUse db/infra/ or manual migration
CREATE CASTUse manual migration
CREATE COLLATIONUse manual migration
CREATE CONVERSIONUse manual migration
CREATE EVENT TRIGGERUse manual migration
CREATE FOREIGN DATA WRAPPERUse manual migration
CREATE LANGUAGEUse manual migration
CREATE OPERATORUse manual migration
CREATE PUBLICATIONUse manual migration
CREATE SERVERUse manual migration
CREATE SUBSCRIPTIONUse manual migration
CREATE TEXT SEARCHUse manual migration
CREATE USER MAPPINGUse manual migration

Other

  • RENAME commands are not supported

How to Handle Unsupported Commands

Option 1: Infrastructure SQL (db/infra/)

Place cluster and database level commands in db/infra/. These are applied before the plan command runs:

db/infra/
├── 001_roles.sql -- CREATE ROLE, CREATE USER
├── 002_schemas.sql -- CREATE SCHEMA
└── 003_extensions.sql -- CREATE EXTENSION

Option 2: Manual Migrations

For one-off SQL operations, use postkit db migration:

# Create a manual migration
postkit db migration <name>

# Edit the generated file in .postkit/db/session/
# Add your SQL (e.g., CREATE EXTENSION, CREATE ROLE, etc.)

# Apply it
postkit db apply

# Commit it
postkit db commit

Examples

Creating Extensions

Preferred — add to db/infra/:

-- db/infra/003_extensions.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pgcrypto;

Fallback — one-off manual migration:

postkit db migration add_uuid_extension
-- migrate:up
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- migrate:down
DROP EXTENSION IF EXISTS "uuid-ossp";

Creating Schemas

Preferred — add to db/infra/:

-- db/infra/002_schemas.sql
CREATE SCHEMA IF NOT EXISTS audit;
CREATE SCHEMA IF NOT EXISTS analytics;

Also update db.schemas in postkit.config.json so PostKit manages the schema's SQL files:

{ "db": { "schemas": ["public", "audit", "analytics"] } }

Fallback — one-off manual migration:

postkit db migration create_custom_schemas
-- migrate:up
CREATE SCHEMA IF NOT EXISTS audit;
CREATE SCHEMA IF NOT EXISTS analytics;
-- migrate:down
DROP SCHEMA IF EXISTS audit;
DROP SCHEMA IF EXISTS analytics;

Creating Roles

Preferred — add to db/infra/:

-- db/infra/001_roles.sql
CREATE ROLE app_read;
CREATE ROLE app_write;
CREATE ROLE app_admin;
GRANT app_read TO app_write;
GRANT app_write TO app_admin;

Fallback — one-off manual migration:

postkit db migration create_app_roles
-- migrate:up
CREATE ROLE app_read;
CREATE ROLE app_write;
CREATE ROLE app_admin;
GRANT app_read TO app_write;
GRANT app_write TO app_admin;
-- migrate:down
DROP ROLE IF EXISTS app_admin;
DROP ROLE IF EXISTS app_write;
DROP ROLE IF EXISTS app_read;

Key Takeaway

The plan command uses pgschema, which only handles schema-level objects. For cluster/database level commands, use db/infra/ or create manual migrations with postkit db migration.