This guide will walk you through the core pgschema workflow: dumping a schema, making edits, planning changes, and applying migrations. By the end, you’ll understand how to manage Postgres schemas declaratively.
This creates a schema.sql file containing your complete schema definition. Let’s look at what it contains:
schema.sql
Copy
-- Example outputCREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT NOW());CREATE INDEX idx_users_email ON users(email);
The output is clean and developer-friendly, unlike the verbose output from pg_dump.
Now, let’s modify the schema.sql file to add new features. Edit the file to include:
schema.sql (modified)
Copy
CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(100), -- New column created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() -- New column);-- New indexCREATE INDEX idx_users_name ON users(name);CREATE INDEX idx_users_email ON users(email);-- New tableCREATE TABLE posts ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), title VARCHAR(200) NOT NULL, content TEXT, created_at TIMESTAMP DEFAULT NOW());
This will save the migration plan to plan.json and print the human-readable version to stdout:
plan.txt
Copy
Plan: 2 to add, 1 to modify.Summary by type: tables: 1 to add, 1 to modify indexes: 1 to addTables: + public.posts ~ public.users + column name + column updated_atIndexes: + public.idx_users_nameTransaction: trueDDL to be executed:--------------------------------------------------ALTER TABLE users ADD COLUMN name VARCHAR(100);ALTER TABLE users ADD COLUMN updated_at TIMESTAMP DEFAULT NOW();CREATE INDEX idx_users_name ON users (name);CREATE TABLE posts ( id SERIAL NOT NULL, user_id integer, title VARCHAR(200) NOT NULL, content text, created_at timestamp DEFAULT NOW(), PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES users (id));
You can also skip the separate planning step and apply changes directly from the schema file:
Copy
# Apply directly from schema file (combines plan + apply)$ PGPASSWORD=testpwd1 pgschema apply \ --host localhost \ --db testdb \ --user postgres \ --schema public \ --file schema.sql
This approach automatically generates the plan internally and applies the changes in one command.
The two-phase workflow (plan then apply) is recommended for production environments where you want to review and save the plan before execution. Direct apply is convenient for development environments.