Skip to content

Quick Start

Get started with pgmt in 10 minutes and see what makes it different from other migration tools.

Terminal window
cargo install pgmt

Don’t have Rust? Install it first:

Terminal window
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

Verify installation:

Terminal window
pgmt --version

pgmt requires PostgreSQL 13 or later. Choose your preferred option:

Docker (Recommended):

Terminal window
docker run -d \
--name pgmt-dev \
-e POSTGRES_PASSWORD=dev \
-e POSTGRES_DB=myapp_dev \
-p 5432:5432 \
postgres:15

Already have PostgreSQL? Just create a database:

Terminal window
createdb myapp_dev
Terminal window
# Create project directory
mkdir my-app && cd my-app
# Initialize pgmt (Docker users)
pgmt init --dev-url postgres://postgres:dev@localhost/myapp_dev --defaults
# For local PostgreSQL without password
# pgmt init --dev-url postgres://localhost/myapp_dev --defaults

This creates:

my-app/
├── schema/ # Your SQL schema files
├── migrations/ # Generated migration files
├── schema_baselines/ # Baseline snapshots (created on-demand)
└── pgmt.yaml # Configuration

Want more control? Run pgmt init without --defaults for an interactive setup that:

  • Shows you exactly what’s in your database (if importing existing schema)
  • Lets you configure which object types to manage (comments, grants, triggers, extensions)
  • Automatically validates generated schema files
  • Provides clear guidance if dependency issues are found

Create a simple table:

Terminal window
cat > schema/users.sql << 'EOF'
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL,
full_name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
EOF

Now add a view that depends on it:

Terminal window
cat > schema/active_users.sql << 'EOF'
-- require: users.sql
CREATE VIEW active_users AS
SELECT * FROM users;
EOF

Notice the -- require: users.sql? This is like import in Python or require in Node.js - it declares dependencies and lets you organize your schema however makes sense for your project.

Apply the schema to your dev database:

Terminal window
pgmt apply

pgmt will:

  • Create a shadow database
  • Load your schema files in dependency order
  • Compare with your dev database
  • Apply the necessary changes

Here’s what makes pgmt special. Let’s rename a column in the base table:

Terminal window
cat > schema/users.sql << 'EOF'
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL, -- Renamed from full_name
created_at TIMESTAMP DEFAULT NOW()
);
EOF

Now apply the change:

Terminal window
pgmt apply

What just happened?

pgmt automatically:

  1. Dropped the active_users view (because the column structure changed)
  2. Renamed the column: ALTER TABLE users RENAME COLUMN full_name TO name
  3. Recreated the active_users view with the same definition

The view file didn’t change - it still says SELECT * FROM users - but pgmt knows it needs to be recreated because the underlying table structure changed.

Let’s add another view that depends on the first one:

Terminal window
cat > schema/recent_users.sql << 'EOF'
-- require: active_users.sql
CREATE VIEW recent_users AS
SELECT * FROM active_users
WHERE created_at > NOW() - INTERVAL '7 days';
EOF

Apply it:

Terminal window
pgmt apply

Now update the active_users view definition to add a filter:

Terminal window
cat > schema/active_users.sql << 'EOF'
-- require: users.sql
CREATE VIEW active_users AS
SELECT * FROM users WHERE email IS NOT NULL; -- Added filter
EOF

Apply again:

Terminal window
pgmt apply

pgmt automatically:

  1. Dropped recent_users (depends on active_users)
  2. Dropped active_users (the view we’re changing)
  3. Created active_users (new definition with filter)
  4. Created recent_users (unchanged, but depends on active_users)

All in the correct order, based on the dependency graph.

With traditional migration tools, you’d manually write:

-- Hope you remember all the dependencies!
DROP VIEW recent_users;
DROP VIEW active_users;
CREATE VIEW active_users AS ...; -- Better get the order right
CREATE VIEW recent_users AS ...;

With pgmt, you edit views and functions like source code. pgmt handles the drop/recreate mechanics, figures out the dependency cascade, and applies changes in the correct order. No manual migration scripts needed.

The -- require: statements aren’t just for dependency resolution - they’re for organizing your schema like a real programming language:

Terminal window
schema/
├── 01_foundation/
└── extensions.sql # PostgreSQL extensions
├── 02_core/
├── users.sql # Core entities
└── posts.sql # require: users.sql
└── 03_features/
└── analytics.sql # require: users.sql, posts.sql

Organize by domain, by feature, by team ownership - whatever makes sense for YOUR project. pgmt handles the dependency graph automatically.

When you’re ready to deploy to production, generate an explicit migration:

Terminal window
pgmt migrate new "initial schema with user views"

This creates a migration file like:

migrations/V1734567890__initial_schema_with_user_views.sql

Review the generated SQL:

Terminal window
cat migrations/V*__initial_schema_with_user_views.sql

You’ll see explicit SQL statements that you can review, test, and version control before deploying to production.

Terminal window
pgmt apply --watch

Automatically applies safe changes as you edit schema files. Prompts for confirmation on destructive operations (like dropping columns).

Terminal window
pgmt apply --dry-run

See what would change without actually applying it.

Terminal window
pgmt migrate status

See which migrations have been applied to your database.

Organize your schema:

Work with a team:

Handle complex changes: