{"id":18893984,"url":"https://github.com/bard/pg_dev","last_synced_at":"2026-06-24T08:32:16.391Z","repository":{"id":66470699,"uuid":"505170017","full_name":"bard/pg_dev","owner":"bard","description":null,"archived":false,"fork":false,"pushed_at":"2022-06-19T17:02:41.000Z","size":91,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-11T15:50:50.985Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bard.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2022-06-19T17:02:17.000Z","updated_at":"2022-06-20T17:19:47.000Z","dependencies_parsed_at":"2023-02-25T02:00:18.629Z","dependency_job_id":null,"html_url":"https://github.com/bard/pg_dev","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bard/pg_dev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bard%2Fpg_dev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bard%2Fpg_dev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bard%2Fpg_dev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bard%2Fpg_dev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bard","download_url":"https://codeload.github.com/bard/pg_dev/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bard%2Fpg_dev/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34724735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-11-08T08:17:09.222Z","updated_at":"2026-06-24T08:32:16.383Z","avatar_url":"https://github.com/bard.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## An experimental source-centric, TDD-friendly SQL schema development workflow for Postgres\n\nDevelopment usually flows from _sources_ to _live_: code, compile, test, commit, push, deploy. Source files are what you look at to know the state of development.\n\nWith SQL development, however, it's not uncommon to start with _live_ (scribbling code in a database admin interface), and end up with migration files that we may call \"sources\" but really are opaque _targets_.\n\nThis makes it harder to reason about code, work in tight feedback loops and controlled environments (as allowed by TDD), and guard against regressions (lacking the unit tests resulting from TDD\\*\\*.\n\n**`pg_dev` facilitates a source-centric workflow for (Postgre)SQL**, where the schema's source is a first-class citizen in the repository — you can view, edit, and test it like any other source — and migrations are automatically derived from schema changes.\n\n**This is alpha software.**\n\n## How it works\n\n1. You write a `schema.sql` file.\n\n2. Optionally (but ideally), you write tests using [pg_tap](https://pgtap.org/) and a file watcher sends schema and tests to a pristine Postgres environment on every change.\n\n3. Once happy, you run `pg_dev generate-migration`, and `pg_dev` looks through git history for the last known schema, diffs it against the current one, and saves the resulting migration.\n\n## Installation\n\n```sh\n$ python -m pip install https://github.com/bard/pg_dev/archive/master.tar.gz\n```\n\n## Tutorial\n\nCreate a git repository:\n\n```sh\n$ mkdir example\n$ cd example\n$ git init\n```\n\nCreate `schema.sql`:\n\n```sql\nCREATE TABLE users (\n  id uuid DEFAULT gen_random_uuid() NOT NULL,\n  name TEXT NOT NULL\n);\n```\n\nCreate the migrations directory and generate the first migration:\n\n```sh\n$ mkdir migrations\n$ pg_dev generate-migration schema.sql migrations\nSchema file name: schema.sql\nMigration directory: migrations\nCurrent schema fingerprint: 7676866d0a1a57cb\nLast migrated schema fingerprint: none\nGenerated migration migrations/000_none-7676866d0a1a57cb.sql\n```\n\nAdd schema and migration to the repository and commit (there is no requirement to do these together, it just makes life easier for those looking at commit log later):\n\n```sh\n$ git add schema.sql migrations/000_none-7676866d0a1a57cb.sql\n$ git commit -m 'add database schema'\n```\n\nMake a change to the schema:\n\n```diff\n  CREATE TABLE users (\n    id uuid DEFAULT gen_random_uuid() NOT NULL,\n+   address TEXT NOT NULL,\n    name TEXT NOT NULL\n  );\n```\n\nGenerate the next migration:\n\n```sh\n$ pg_dev generate-migration schema.sql migrations\nSchema file name: schema.sql\nMigration directory: migrations\nCurrent schema fingerprint: 293a4f7b996ccceb\nLast migrated schema fingerprint: 7676866d0a1a57cb\nLast migrated schema commit: 4b095f75a874739a4f6cfc71e92dd61ba0cf75e8\nGenerated migration migrations/001_7676866d0a1a57cb-293a4f7b996ccceb.sql\n```\n\nAdd commit changes:\n\n```sh\n$ git add schema.sql migrations/001_7676866d0a1a57cb-293a4f7b996ccceb.sql\n$ git commit -m 'add address column'\n```\n\nInspect the schema history so far:\n\n```sh\n$ pg_dev history schema.sql\nfingerprint       commit message       commit hash\n----------------  -------------------  ----------------------------------------\n293a4f7b996ccceb  add address column   cb3f41c51be0f5a4b72b4b70985ad438e172cb09\n7676866d0a1a57cb  add database schema  4b095f75a874739a4f6cfc71e92dd61ba0cf75e8\n```\n\n## Q\u0026A\n\n### Does `pg_dev` generate migrations also on non-functional changes such as formatting, comments, or order of columns?\n\nNo, `pg_dev` identifies schemas by finger-printing their _normalized_ versions, so those changes won't cause a migration.\n\n### Does `pg_dev` manage data migration?\n\n`pg_dev` only deals with DDL, however, you can manually extend migrations to account for data if desired.\n\n### How do I use this for TDD?\n\nFuture versions of `pg_dev` will support watching files and running tests against an internally managed [ephemeral Postgres instance](https://eradman.com/ephemeralpg/) or Postgres Docker image, or an external arbitrary Postgres instance.\n\nFor now, you'll have to provide a running Postgres instance, ensure it has access to the `pg_tap` extension (on Debian-based systems, install the `postgresql-13-pgtap` package), and run the provided [examples/run-test.sh](./examples/tdd/run-test.sh) script under a file watcher such as [watchexec](https://github.com/watchexec/watchexec).\n\nFor a complete worked example:\n\n```sh\n$ cd examples/tdd\n$ docker-compose up -d # starts postgres+pgtap in container\n$ watchexec -w schema.sql -w tests \"./run-tests.sh tests/*\"\n```\n\nThen edit `schema.sql` or files under `tests/`.\n\n### Can I use any Postgres-supported SQL in defining a schema?\n\nThe current diff engine, [migra](https://github.com/djrobstep/migra), has good coverage of DDL constructs with a few notable [exceptions](https://databaseci.com/docs/migra). In those cases, you'll have to fall back on editing migration files after generating them.\n\nA future version of `pg_dev` might switch to the diff engine from [pgAdmin](https://www.pgadmin.org/), Postgres's official administration tool.\n\n### Can I split my schema into multiple files and import them with `\\i`?\n\nOnly a single schema file is supported at the moment.\n\n# Caveats\n\nRewriting past versions of the schema file will change their fingerprint, making it impossible for `pg_dev` to do its work.\n\n## Development\n\nTo run tests:\n\n```sh\n$ poetry run task test\n```\n\n## Resources\n\n- [Overcoming First Principles — A guide for accessing the features of PostgreSQL in test-driven development](https://eradman.com/talks/overcoming_first_principles/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbard%2Fpg_dev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbard%2Fpg_dev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbard%2Fpg_dev/lists"}