{"id":34751100,"url":"https://github.com/fmguerreiro/pgmold","last_synced_at":"2026-05-03T10:05:45.864Z","repository":{"id":325418659,"uuid":"1101095558","full_name":"fmguerreiro/pgmold","owner":"fmguerreiro","description":"PostgreSQL schema-as-code management tool","archived":false,"fork":false,"pushed_at":"2026-04-13T05:11:17.000Z","size":240364,"stargazers_count":10,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-13T05:12:17.222Z","etag":null,"topics":["cli","database","devops","migrations","postgresql","rust","schema"],"latest_commit_sha":null,"homepage":"https://pgmold.dev","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fmguerreiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-21T07:26:00.000Z","updated_at":"2026-04-13T05:02:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fmguerreiro/pgmold","commit_stats":null,"previous_names":["fmguerreiro/pgmold"],"tags_count":129,"template":false,"template_full_name":null,"purl":"pkg:github/fmguerreiro/pgmold","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fmguerreiro%2Fpgmold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fmguerreiro%2Fpgmold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fmguerreiro%2Fpgmold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fmguerreiro%2Fpgmold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fmguerreiro","download_url":"https://codeload.github.com/fmguerreiro/pgmold/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fmguerreiro%2Fpgmold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31747172,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T09:16:15.125Z","status":"ssl_error","status_checked_at":"2026-04-13T09:16:05.023Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","database","devops","migrations","postgresql","rust","schema"],"created_at":"2025-12-25T05:17:04.058Z","updated_at":"2026-05-03T10:05:45.840Z","avatar_url":"https://github.com/fmguerreiro.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"pgmold\" width=\"200\"\u003e\n\u003c/p\u003e\n\n# pgmold\n\nPostgreSQL schema-as-code management tool. Define schemas in native PostgreSQL DDL, diff against live databases, plan migrations, and apply them safely.\n\n## Features\n\n- **Schema-as-Code**: Define PostgreSQL schemas in native SQL DDL files\n- **Introspection**: Read schema from live PostgreSQL databases\n- **Diffing**: Compare schemas and generate migration plans\n- **Safety**: Lint rules prevent destructive operations without explicit flags\n- **Drift Detection**: Detect schema drift in CI/CD\n- **Transactional Apply**: All migrations run in a single transaction\n- **Partitioned Tables**: Full support for `PARTITION BY` and `PARTITION OF` syntax\n- **JSON Output**: Machine-readable output for all commands via `--json` / `-j`\n- **Describe**: Inspect available commands, object types, and providers with `pgmold describe`\n- **Grant Management**: `GRANT`/`REVOKE` sync enabled by default; `--manage-ownership` for `ALTER OWNER`\n- **Environment Variable**: Set connection string via `PGMOLD_DATABASE_URL`\n- **PostgreSQL 13-17**: Tested against every major version ([compatibility matrix](https://pgmold.dev/docs/reference/compatibility/))\n\n## How pgmold Works\n\n```\n┌─────────────────────┐     ┌─────────────────────┐\n│   Schema Files      │     │   Live Database     │\n│   (Desired State)   │     │   (Current State)   │\n└──────────┬──────────┘     └──────────┬──────────┘\n           │                           │\n           └───────────┬───────────────┘\n                       ▼\n              ┌─────────────────┐\n              │   pgmold diff   │\n              │   (compare)     │\n              └────────┬────────┘\n                       ▼\n              ┌─────────────────┐\n              │  Generated SQL  │\n              │  (only changes) │\n              └─────────────────┘\n```\n\n**Example:**\n\nYour schema file says:\n```sql\nCREATE TABLE users (\n  id UUID PRIMARY KEY,\n  name TEXT NOT NULL,\n  email TEXT NOT NULL,  -- NEW\n  created_at TIMESTAMP\n);\n```\n\nDatabase currently has:\n```sql\nCREATE TABLE users (\n  id UUID PRIMARY KEY,\n  name TEXT NOT NULL,\n  created_at TIMESTAMP\n);\n```\n\npgmold generates only the delta:\n```sql\nALTER TABLE users ADD COLUMN email TEXT NOT NULL;\n```\n\n## Installation\n\n```bash\ncargo install pgmold\n```\n\nFor the latest version from source:\n\n```bash\ncargo install --git https://github.com/fmguerreiro/pgmold\n```\n\n## Quick Start\n\n```bash\n# 1. Create a schema file\ncat \u003e schema.sql \u003c\u003c 'EOF'\nCREATE TABLE users (\n    id BIGINT PRIMARY KEY,\n    email TEXT NOT NULL,\n    created_at TIMESTAMP DEFAULT now()\n);\nEOF\n\n# 2. See what would change\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb\n\n# 3. Apply the migration\npgmold apply -s sql:schema.sql -d postgres://localhost/mydb\n```\n\n## Usage\n\n```bash\n# Diff two SQL schema files (outputs migration SQL)\npgmold diff --from sql:old.sql --to sql:new.sql\n\n# Diff with JSON output for CI\npgmold diff --from sql:old.sql --to sql:new.sql --json\n\n# Generate migration plan\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb\n\n# Generate rollback plan (reverse direction)\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb --reverse\n\n# Apply migrations (with safety checks)\npgmold apply -s sql:schema.sql -d postgres://localhost/mydb\n\n# Apply with destructive operations allowed\npgmold apply -s sql:schema.sql -d postgres://localhost/mydb --allow-destructive\n\n# Dry run (preview SQL without executing)\npgmold apply -s sql:schema.sql -d postgres://localhost/mydb --dry-run\n\n# Lint schema (requires a database connection to resolve types)\npgmold lint -s sql:schema.sql -d postgres://localhost/mydb\n\n# Detect drift (returns JSON report with exit code 1 if drift detected)\npgmold drift -s sql:schema.sql -d postgres://localhost/mydb -j\n```\n\n## Guides\n\n### Multi-File Schemas\n\nOrganize your schema across multiple files using directories or glob patterns:\n\n```bash\n# Load all SQL files from a directory (recursive)\npgmold apply -s sql:./schema/ -d postgres://localhost/mydb\n\n# Use glob patterns\npgmold apply -s \"sql:schema/**/*.sql\" -d postgres://localhost/mydb\n\n# Multiple sources\npgmold apply -s sql:types.sql -s \"sql:tables/*.sql\" -d postgres://localhost/mydb\n```\n\nExample directory structure:\n```\nschema/\n├── enums.sql           # CREATE TYPE statements\n├── tables/\n│   ├── users.sql       # users table + indexes\n│   └── posts.sql       # posts table + foreign keys\n└── functions/\n    └── triggers.sql    # stored procedures\n```\n\nDuplicate definitions across files produce an error with file locations.\n\n### Filtering Objects\n\nFilter by name patterns or object types.\n\n**Filter by name pattern:**\n```bash\n# Include only objects matching patterns\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --include 'api_*' --include 'users'\n\n# Exclude objects matching patterns\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --exclude '_*' --exclude 'pg_*'\n```\n\n**Filter by object type:**\n```bash\n# Only compare tables and functions (ignore extensions, views, triggers, etc.)\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --include-types tables,functions\n\n# Exclude extensions from comparison\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --exclude-types extensions\n```\n\n**Combine type and name filters:**\n```bash\n# Compare only functions matching 'api_*', excluding internal ones\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --include-types functions \\\n  --include 'api_*' \\\n  --exclude '_*'\n```\n\n**Filter nested types within tables:**\n```bash\n# Compare tables without RLS policies\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --exclude-types policies\n\n# Compare only table structure (no indexes, constraints, or policies)\npgmold plan -s sql:schema.sql -d postgres://localhost/mydb \\\n  --exclude-types policies,indexes,foreignkeys,checkconstraints\n```\n\nAvailable object types:\n- Top-level: `extensions`, `tables`, `enums`, `domains`, `functions`, `views`, `triggers`, `sequences`, `partitions`\n- Nested (within tables): `policies`, `indexes`, `foreignkeys`, `checkconstraints`\n\n### Extension Objects\n\nBy default, pgmold excludes objects owned by extensions (e.g., PostGIS functions, pg_trgm operators) from diffs.\n\n```bash\n# Include extension objects if needed (e.g., for full database dumps)\npgmold dump -d postgres://localhost/mydb --include-extension-objects -o full_schema.sql\n```\n\n### Adopting pgmold in an Existing Project\n\nUse `pgmold dump` to create a baseline from a live database:\n\n```bash\n# Export current database schema to SQL files\npgmold dump -d postgres://localhost/mydb -o schema/baseline.sql\n\n# For specific schemas only\npgmold dump -d postgres://localhost/mydb --target-schemas public,auth -o schema/baseline.sql\n\n# Split into multiple files by object type\npgmold dump -d postgres://localhost/mydb --split -o schema/\n```\n\nThe `--split` option creates separate files for extensions, types, sequences, tables, functions, views, triggers, and policies.\n\nAfter this, your schema files match the database exactly and `pgmold plan` shows zero operations.\n\n#### Workflow After Baseline\n\n1. **Make changes** by editing the SQL schema files\n2. **Preview** with `pgmold plan -s sql:schema/ -d postgres://localhost/mydb`\n3. **Apply** with `pgmold apply -s sql:schema/ -d postgres://localhost/mydb`\n\n#### Integrating with Existing Migration Systems\n\npgmold is declarative -- it computes diffs and applies directly. To maintain compatibility with an existing migration system:\n\n```bash\n# Generate a numbered migration file automatically\npgmold migrate \\\n  -s sql:schema/ \\\n  -d postgres://localhost/mydb \\\n  --migrations ./migrations \\\n  --name \"add_email_column\"\n# Creates: migrations/0044_add_email_column.sql\n\n# Or manually capture output\npgmold diff --from sql:current.sql --to sql:schema/ \u003e migrations/0044_my_change.sql\n```\n\nThe `migrate` command auto-detects the next migration number. Use pgmold for diffing while keeping your existing migration runner.\n\n### CI Integration\n\npgmold includes a GitHub Action for schema CI: migration plan comments, drift detection, PR auto-labeling, and warning annotations.\n\n#### GitHub Action Usage\n\n```yaml\n- uses: fmguerreiro/pgmold/.github/actions/drift-check@main\n  with:\n    schema: sql:schema/\n    database: db:${{ secrets.DATABASE_URL }}\n    target-schemas: public,auth\n```\n\nThe action runs in two modes:\n\n- **Live database mode**: Requires `database`. Generates a migration plan, posts it as a PR comment, and optionally checks for drift.\n- **SQL-to-SQL baseline mode**: Requires `baseline`. Diffs `schema` against a baseline SQL file — no live database needed.\n\n**Key inputs:**\n- `schema` (required): Schema source(s), space-separated.\n- `database`: PostgreSQL connection string. Required unless `baseline` is set.\n- `baseline`: `sql:path/to/baseline.sql` for SQL-to-SQL diff mode.\n- `target-schemas`: Comma-separated PostgreSQL schemas. Default: `public`.\n- `fail-on-drift`: Fail if drift detected. Default: `true`.\n- `plan-comment`: Post migration plan as a PR comment. Default: `true`.\n- `drift-check`: Run drift detection. Default: `true`.\n- `auto-label`: Add `database-schema` label to the PR when schema changes are detected. Default: `true`.\n\n**Outputs:**\n- `has-drift`: Whether drift was detected (true/false).\n- `expected-fingerprint`: Expected schema fingerprint from SQL files.\n- `actual-fingerprint`: Actual schema fingerprint from database.\n- `report`: Full JSON drift report.\n- `plan-json`: Full plan JSON output.\n- `statement-count`: Number of SQL statements in the migration plan.\n- `has-destructive`: Whether the plan contains destructive operations.\n- `comment-id`: ID of the PR comment posted or updated.\n\nSee `.github/actions/drift-check/README.md` for full documentation and `.github/workflows/examples/schema-check.yml` for a complete example.\n\n#### CLI Drift Detection\n\nFor local or custom CI environments, use the `drift` command directly:\n\n```bash\n# Get JSON report with exit code 1 if drift detected\npgmold drift -s sql:schema/ -d postgres://localhost/mydb --json\n```\n\nOutput:\n```json\n{\n  \"has_drift\": true,\n  \"expected_fingerprint\": \"abc123...\",\n  \"actual_fingerprint\": \"def456...\",\n  \"differences\": [\"AddColumn { schema: \\\"public\\\", table: \\\"users\\\", ... }\"]\n}\n```\n\nDrift detection compares SHA256 fingerprints of normalized schemas. Any difference triggers drift.\n\n## Terraform Provider\n\npgmold is available as a Terraform provider for infrastructure-as-code workflows.\n\n### Installation\n\n```hcl\nterraform {\n  required_providers {\n    pgmold = {\n      source  = \"fmguerreiro/pgmold\"\n      version = \"~\u003e 0.3\"\n    }\n  }\n}\n\nprovider \"pgmold\" {}\n```\n\n### Usage\n\n```hcl\nresource \"pgmold_schema\" \"app\" {\n  schema_file       = \"${path.module}/schema.sql\"\n  database_url      = var.database_url\n  allow_destructive = false  # Set true to allow DROP operations\n}\n```\n\nTerraform diffs against the live database and applies only necessary migrations on changes.\n\n### Attributes\n\n| Name | Type | Required | Description |\n|------|------|----------|-------------|\n| `schema_file` | string | yes | Path to SQL schema file |\n| `database_url` | string | yes | PostgreSQL connection URL |\n| `target_schemas` | list(string) | no | PostgreSQL schemas to manage (default: `[\"public\"]`) |\n| `allow_destructive` | bool | no | Allow DROP operations (default: `false`) |\n\n**Computed attributes:**\n- `id` - Resource identifier\n- `schema_hash` - SHA256 hash of schema file\n- `applied_at` - Timestamp of last migration\n- `migration_count` - Number of operations applied\n\n### Migration Resource\n\nGenerate numbered migration files instead of applying directly:\n\n```hcl\nresource \"pgmold_migration\" \"app\" {\n  schema_file  = \"${path.module}/schema.sql\"\n  database_url = var.database_url\n  output_dir   = \"${path.module}/migrations\"\n  prefix       = \"V\"  # Flyway-style prefix\n}\n```\n\n## Safety Rules\n\nBy default, pgmold blocks destructive operations:\n\n- `DROP TABLE`, `DROP COLUMN`, `DROP ENUM` require `--allow-destructive`\n- Type narrowing and `SET NOT NULL` produce warnings\n\nSet `PGMOLD_PROD=1` for production mode, which blocks table drops entirely.\n\n## Comparison with Other Tools\n\n### vs Declarative Schema-as-Code Tools\n\nThese tools share pgmold's approach: define desired state, compute diffs automatically.\n\n| Feature | pgmold | [Atlas](https://atlasgo.io/) | [pg-schema-diff](https://github.com/stripe/pg-schema-diff) | [pgschema](https://www.pgschema.com/) |\n|---------|--------|-------|----------------|----------|\n| **Language** | Rust | Go | Go | Go |\n| **Schema Format** | Native SQL | HCL, SQL, ORM | Native SQL | SQL |\n| **Multi-DB Support** | PostgreSQL | ✅ Many | PostgreSQL | PostgreSQL |\n| **Drift Detection** | ✅ | ✅ | ❌ | ❌ |\n| **Lock Hazard Warnings** | ✅ | ✅ | ✅ | ❌ |\n| **Safety Linting** | ✅ | ✅ | ❌ | ❌ |\n| **RLS Policies** | ✅ | ✅ | ❌ | ✅ |\n| **Partitioned Tables** | ✅ | ✅ | ✅ | ⚠️ parent only[^pgschema-partitions] |\n| **Cloud Service** | ❌ | Atlas Cloud | ❌ | ❌ |\n| **Library Mode** | ❌ | ❌ | ✅ | ❌ |\n\n[^pgschema-partitions]: pgschema v1.9.0 dumps the parent's `PARTITION BY` clause correctly but emits children as standalone `CREATE TABLE` statements without `PARTITION OF`, so re-applying a dump loses the partition hierarchy.\n\n### vs Migration-Based Tools\n\nTraditional tools where you write numbered migration files manually.\n\n| Feature | pgmold | Flyway | Liquibase | Sqitch |\n|---------|--------|--------|-----------|--------|\n| **Approach** | Declarative | Versioned | Versioned | Plan-based |\n| **Auto-generates Migrations** | ✅ | ❌ | ❌ | ❌ |\n| **Multi-DB Support** | PostgreSQL | ✅ Many | ✅ Many | ✅ Many |\n| **Drift Detection** | ✅ | ✅ (preview) | ✅ | ❌ |\n| **Rollback Scripts** | Auto (reverse diff) | Manual | Manual | Required |\n| **Enterprise Features** | ❌ | Teams edition | Pro edition | ❌ |\n\n### When to Choose pgmold\n\n- **Pure SQL schemas** -- no HCL or DSLs to learn\n- **PostgreSQL-only** projects needing deep PG integration\n- **Single binary** -- no JVM/Go runtime required\n- **CI/CD drift detection**\n- **Safety-first** workflows with destructive operation guardrails\n- **RLS policies** as first-class citizens\n\n### When to Choose Alternatives\n\n- **Multi-database support** → [Atlas](https://atlasgo.io/), [Flyway](https://flywaydb.org), [Liquibase](https://www.liquibase.org/)\n- **HCL/Terraform-style syntax** → [Atlas](https://atlasgo.io/)\n- **Embeddable Go library** → [pg-schema-diff](https://github.com/stripe/pg-schema-diff)\n- **Zero-downtime migrations** → [pgroll](https://github.com/xataio/pgroll), [Reshape](https://github.com/fabianlindfors/reshape)\n- **Enterprise compliance/audit** → [Liquibase](https://www.liquibase.org/), [Bytebase](https://www.bytebase.com/)\n- **Managed cloud service** → [Atlas Cloud](https://atlasgo.io/cloud/getting-started)\n\n## Development\n\n```bash\n# Build\ncargo build\n\n# Test\ncargo test\n\n# Run integration tests (requires Docker)\ncargo test --test integration\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffmguerreiro%2Fpgmold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffmguerreiro%2Fpgmold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffmguerreiro%2Fpgmold/lists"}