{"id":13683504,"url":"https://github.com/graphile/migrate","last_synced_at":"2025-05-14T03:11:29.630Z","repository":{"id":34641213,"uuid":"173320732","full_name":"graphile/migrate","owner":"graphile","description":"Opinionated SQL-powered productive roll-forward migration tool for PostgreSQL.","archived":false,"fork":false,"pushed_at":"2024-12-23T10:07:07.000Z","size":1286,"stargazers_count":773,"open_issues_count":30,"forks_count":60,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-19T08:51:47.069Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/graphile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","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},"funding":{"github":"Benjie"}},"created_at":"2019-03-01T15:01:47.000Z","updated_at":"2025-04-16T16:04:02.000Z","dependencies_parsed_at":"2024-01-06T07:54:11.734Z","dependency_job_id":"4fb9bcb7-1537-44aa-94e3-700bc7f99b25","html_url":"https://github.com/graphile/migrate","commit_stats":{"total_commits":322,"total_committers":26,"mean_commits":"12.384615384615385","dds":0.3291925465838509,"last_synced_commit":"a5dfe762b73f696fd98f2829fb2e83d8ee9af6d0"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fmigrate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fmigrate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fmigrate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphile%2Fmigrate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphile","download_url":"https://codeload.github.com/graphile/migrate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059519,"owners_count":22007771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-08-02T13:02:13.547Z","updated_at":"2025-05-14T03:11:24.608Z","avatar_url":"https://github.com/graphile.png","language":"TypeScript","funding_links":["https://github.com/sponsors/Benjie"],"categories":["TypeScript"],"sub_categories":[],"readme":"# graphile-migrate\n\n[![Discord chat room](https://img.shields.io/discord/489127045289476126.svg)](http://discord.gg/graphile)\n[![Package on npm](https://img.shields.io/npm/v/graphile-migrate.svg?style=flat)](https://www.npmjs.com/package/graphile-migrate)\n![MIT license](https://img.shields.io/npm/l/graphile-migrate.svg)\n[![Follow](https://img.shields.io/badge/twitter-@GraphileHQ-blue.svg)](https://twitter.com/GraphileHQ)\n\nOpinionated SQL-powered productive roll-forward migration tool for PostgreSQL.\n\n\u003c!-- SPONSORS_BEGIN --\u003e\n\n## Crowd-funded open-source software\n\nTo help us develop this software sustainably, we ask all individuals and\nbusinesses that use it to help support its ongoing maintenance and development\nvia sponsorship.\n\n### [Click here to find out more about sponsors and sponsorship.](https://www.graphile.org/sponsor/)\n\nAnd please give some love to our featured sponsors 🤩:\n\n\u003ctable\u003e\u003ctr\u003e\n\u003ctd align=\"center\"\u003e\u003ca href=\"https://www.the-guild.dev/\"\u003e\u003cimg src=\"https://graphile.org/images/sponsors/theguild.png\" width=\"90\" height=\"90\" alt=\"The Guild\" /\u003e\u003cbr /\u003eThe Guild\u003c/a\u003e *\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\u003ca href=\"https://dovetailapp.com/\"\u003e\u003cimg src=\"https://graphile.org/images/sponsors/dovetail.png\" width=\"90\" height=\"90\" alt=\"Dovetail\" /\u003e\u003cbr /\u003eDovetail\u003c/a\u003e *\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\u003ca href=\"https://stellate.co/\"\u003e\u003cimg src=\"https://graphile.org/images/sponsors/Stellate.png\" width=\"90\" height=\"90\" alt=\"Stellate\" /\u003e\u003cbr /\u003eStellate\u003c/a\u003e *\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\u003ca href=\"https://gosteelhead.com/\"\u003e\u003cimg src=\"https://graphile.org/images/sponsors/steelhead.svg\" width=\"90\" height=\"90\" alt=\"Steelhead\" /\u003e\u003cbr /\u003eSteelhead\u003c/a\u003e *\u003c/td\u003e\n\u003c/tr\u003e\u003ctr\u003e\n\u003ctd align=\"center\"\u003e\u003ca href=\"\"\u003e\u003cimg src=\"https://graphile.org/images/sponsors/latchbio.jpg\" width=\"90\" height=\"90\" alt=\"LatchBio\" /\u003e\u003cbr /\u003eLatchBio\u003c/a\u003e *\u003c/td\u003e\n\u003c/tr\u003e\u003c/table\u003e\n\n\u003cem\u003e\\* Sponsors the entire Graphile suite\u003c/em\u003e\n\n\u003c!-- SPONSORS_END --\u003e\n\n## Why?\n\n- fast iteration speed — save a file and database is updated in milliseconds\n- roll-forward only — maintaining rollbacks is a chore, and in 10 years of API\n  development I've never ran one in production\n- familiar — no custom DSL to learn, just use PostgreSQL syntax\n- fully functional — sending SQL commands directly to PostgreSQL means you can\n  use all of PostgreSQL's features\n- complements [PostGraphile](https://graphile.org/postgraphile/) — works with\n  any application, but PostGraphile's watch mode means that the GraphQL schema\n  is instantly regenerated (without server restart) whenever the database\n  changes\n\n## Opinions\n\n- Local iteration should be easy and _fast_\n- Migrating should be fast\n- Once deployed, databases should be identical (including subtleties such as\n  column order)\n- Migration software should not be tied to a particular application stack\n- Migrations should be written in SQL\n- Roll-forward only (production issues should be fixed via additional\n  migrations, development can iterate current migration)\n- Once a migration is signed off (deployable) it should never be edited\n- Use PostgreSQL ;)\n- Development databases are cheap; can run multiple\n- Resetting development database is acceptable if absolutely necessary\n- Production databases are critical - NEVER RESET\n- Migrating data (as well as DDL) is acceptable, but should be kept to fast\n  operations (or trigger a background job)\n- Migrations should automatically be wrapped in transactions by default\n- Migrations that require execution outside of a transaction (e.g. to enable\n  augmenting non-DDL-safe things, such as `ENUM`s in PostgreSQL) should be\n  explicitly marked\n- Migrations should not pollute PostgreSQL global settings (e.g. use `SET LOCAL`\n  rather than `SET`)\n- Roles should be managed outside of migrations (since they can be shared\n  between databases)\n- Certain schemas are managed by other tools and should not be interfered with;\n  e.g. `graphile_worker`\n\n## Setup\n\nIn development, `graphile-migrate` uses two databases: the main database and a\n\"shadow\" database. The \"shadow\" database is used internally by\n`graphile-migrate` to test the consistency of the migrations and perform various\nother tasks.\n\nIn production, most users only run `graphile-migrate migrate` which operates\nsolely on the main database - there is no need for a shadow database in\nproduction.\n\nAll members of your team should run the same PostgreSQL version to ensure that\nthe shadow dump matches for everyone (one way of achieving this is through\nDocker, but that isn't required).\n\nWe recommend dumping your database schema with `pg_dump` after migrations are\ncompleted; you can\n[see an example of this in Graphile Starter](https://github.com/graphile/starter/blob/4854f77e461062a95cdfff9c62082eb90a3a0d5b/%40app/db/.gmrc#L20).\nTracking this file in git will allow you to easily see the changes that\ndifferent migrations are making, so you can be sure you're making the changes\nyou intend to. We recommend that you dump the shadow database as it will be\nunaffected by the iteration you've been applying to your development database\n(which may have come out of sync - see 'Drift' below).\n\n### Getting started\n\n\u003e These instructions are for starting a new database project with Graphile\n\u003e Migrate; if you already have a database schema, see\n\u003e [Using Migrate with an existing database](#using-migrate-with-an-existing-database)\n\u003e for some tips.\n\nCreate your database role (if desired), database and shadow database:\n\n```bash\ncreateuser --pwprompt dbowner\ncreatedb myapp --owner=dbowner\ncreatedb myapp_shadow --owner=dbowner\n```\n\n\u003e For an in depth-discussion on the different users and roles typically involved\n\u003e in database and migration management, please see issue\n\u003e [#215](https://github.com/graphile/migrate/issues/215).\n\nExport your database URL, shadow database URL, and a \"root\" database URL which\nshould be a superuser account connection to any **other** database (most\nPostgreSQL servers have a default database called `postgres` which is a good\nchoice for this).\n\n```bash\nexport DATABASE_URL=\"postgres://dbowner:password@localhost/myapp\"\nexport SHADOW_DATABASE_URL=\"postgres://dbowner:password@localhost/myapp_shadow\"\n\nexport ROOT_DATABASE_URL=\"postgres://postgres:postgres@localhost/postgres\"\n```\n\n\u003e Your database URL is needed for most Graphile Migrate commands. The shadow\n\u003e database URL is needed for the development-only commands `commit`, `uncommit`\n\u003e and `reset`. The root database URL is needed to drop and recreate databases,\n\u003e i.e. for the `reset` command and for commands that call it (`commit` and\n\u003e `uncommit`, which reset the shadow database).\n\u003e\n\u003e **NOTE**: you should not need the shadow database URL or root database URL in\n\u003e production (you only need the `graphile-migrate migrate` command in\n\u003e production) unless you have actions that need them.\n\nThen run:\n\n```bash\ngraphile-migrate init\n```\n\nAt this point you should be ready to use Graphile Migrate. You may want to store\nthese environmental variables to a file so you can easily source them (with the\n`.` command in bash, for example) in future:\n\n```bash\n. ./.env\ngraphile-migrate watch\n```\n\n## Usage\n\n### Committed and current migrations\n\nNew migrations are composed within **\"the current migration\"**. You will see\nthis term used a lot. By default this is in the `migrations/current.sql` file,\nbut if you like you may delete that file and instead create a\n`migrations/current/` folder into which you may place numbered SQL files which\ntogether comprise \"the current migration\".\n\nThe current migration should be idempotent (this is your responsibility, see\n\"Idempotency\" below); i.e. it should be able to be ran multiple times and have\nthe same result. This is critical for `graphile-migrate watch`, which is one of\nthe main selling points of the project.\n\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- CLI_USAGE_BEGIN --\u003e\n## graphile-migrate\n\n```\ngraphile-migrate \u003ccommand\u003e\n\nCommands:\n  graphile-migrate init            Initializes a graphile-migrate project by\n                                   creating a `.gmrc` file and `migrations`\n                                   folder.\n  graphile-migrate migrate         Runs any un-executed committed migrations.\n                                   Does NOT run the current migration. For use\n                                   in production and development.\n  graphile-migrate watch           Runs any un-executed committed migrations and\n                                   then runs and watches the current migration,\n                                   re-running it on any change. For development.\n  graphile-migrate commit          Commits the current migration into the\n                                   `committed/` folder, resetting the current\n                                   migration. Resets the shadow database.\n  graphile-migrate uncommit        This command is useful in development if you\n                                   need to modify your latest commit before you\n                                   push/merge it, or if other DB commits have\n                                   been made by other developers and you need to\n                                   'rebase' your migration onto theirs. Moves\n                                   the latest commit out of the committed\n                                   migrations folder and back to the current\n                                   migration (assuming the current migration is\n                                   empty-ish). Removes the migration tracking\n                                   entry from ONLY the local database. Do not\n                                   use after other databases have executed this\n                                   committed migration otherwise they will fall\n                                   out of sync. Assuming nothing else has\n                                   changed, `graphile-migrate uncommit \u0026\u0026\n                                   graphile-migrate commit` should result in the\n                                   exact same hash. Development only, and liable\n                                   to cause conflicts with other developers - be\n                                   careful.\n  graphile-migrate status          Exits with a bitmap status code indicating\n                                   statuses:\n\n                                   - 1 if there are committed migrations that\n                                   have not been executed yet (requires DB\n                                   connection)\n                                   - 2 if the current migration is non-empty\n                                   (ignoring comments)\n\n                                   If both of the above are true then the output\n                                   status will be 3 (1+2). If neither\n                                   are true, exit status will be 0 (success).\n                                   Additional messages may also be output.\n  graphile-migrate reset           Drops and re-creates the database, re-running\n                                   all committed migrations from the start.\n                                   **HIGHLY DESTRUCTIVE**.\n  graphile-migrate compile [file]  Compiles a SQL file, inserting all the\n                                   placeholders and returning the result to\n                                   STDOUT\n  graphile-migrate run [file]      Compiles a SQL file, inserting all the\n                                   placeholders, and then runs it against the\n                                   database. Useful for seeding. If called from\n                                   an action will automatically run against the\n                                   same database (via GM_DBURL envvar) unless\n                                   --shadow or --rootDatabase are supplied.\n  graphile-migrate completion      Generate shell completion script.\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n\nYou are running graphile-migrate v2.0.0-rc.1.\n```\n\n\n## graphile-migrate init\n\n```\ngraphile-migrate init\n\nInitializes a graphile-migrate project by creating a `.gmrc` file and\n`migrations` folder.\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n      --folder  Use a folder rather than a file for the current migration.\n                                                      [boolean] [default: false]\n```\n\n\n## graphile-migrate migrate\n\n```\ngraphile-migrate migrate\n\nRuns any un-executed committed migrations. Does NOT run the current migration.\nFor use in production and development.\n\nOptions:\n      --help          Show help                                        [boolean]\n  -c, --config        Optional path to gmrc file\n                                             [string] [default: .gmrc[.js|.cjs]]\n      --shadow        Apply migrations to the shadow DB (for development).\n                                                      [boolean] [default: false]\n      --forceActions  Run beforeAllMigrations and afterAllMigrations actions\n                      even if no migration was necessary.\n                                                      [boolean] [default: false]\n```\n\n\n## graphile-migrate watch\n\n```\ngraphile-migrate watch\n\nRuns any un-executed committed migrations and then runs and watches the current\nmigration, re-running it on any change. For development.\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n      --once    Runs the current migration and then exits.\n                                                      [boolean] [default: false]\n      --shadow  Applies changes to shadow DB.         [boolean] [default: false]\n```\n\n\n## graphile-migrate commit\n\n```\ngraphile-migrate commit\n\nCommits the current migration into the `committed/` folder, resetting the\ncurrent migration. Resets the shadow database.\n\nOptions:\n      --help     Show help                                             [boolean]\n  -c, --config   Optional path to gmrc file  [string] [default: .gmrc[.js|.cjs]]\n  -m, --message  Optional commit message to label migration, must not contain\n                 newlines.                                              [string]\n```\n\n\n## graphile-migrate uncommit\n\n```\ngraphile-migrate uncommit\n\nThis command is useful in development if you need to modify your latest commit\nbefore you push/merge it, or if other DB commits have been made by other\ndevelopers and you need to 'rebase' your migration onto theirs. Moves the latest\ncommit out of the committed migrations folder and back to the current migration\n(assuming the current migration is empty-ish). Removes the migration tracking\nentry from ONLY the local database. Do not use after other databases have\nexecuted this committed migration otherwise they will fall out of sync. Assuming\nnothing else has changed, `graphile-migrate uncommit \u0026\u0026 graphile-migrate commit`\nshould result in the exact same hash. Development only, and liable to cause\nconflicts with other developers - be careful.\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n```\n\n\n## graphile-migrate reset\n\n```\ngraphile-migrate reset\n\nDrops and re-creates the database, re-running all committed migrations from the\nstart. **HIGHLY DESTRUCTIVE**.\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n      --shadow  Applies migrations to shadow DB.      [boolean] [default: false]\n      --erase   This is your double opt-in to make it clear this DELETES\n                EVERYTHING.                           [boolean] [default: false]\n```\n\n\n## graphile-migrate status\n\n```\ngraphile-migrate status\n\nExits with a bitmap status code indicating statuses:\n\n- 1 if there are committed migrations that have not been executed yet (requires\nDB connection)\n- 2 if the current migration is non-empty (ignoring comments)\n\nIf both of the above are true then the output status will be 3 (1+2). If neither\nare true, exit status will be 0 (success). Additional messages may also be\noutput.\n\nOptions:\n      --help          Show help                                        [boolean]\n  -c, --config        Optional path to gmrc file\n                                             [string] [default: .gmrc[.js|.cjs]]\n      --skipDatabase  Skip checks that require a database connection.\n                                                      [boolean] [default: false]\n```\n\n\n## graphile-migrate compile\n\n```\ngraphile-migrate compile [file]\n\nCompiles a SQL file, inserting all the placeholders and returning the result to\nSTDOUT\n\nOptions:\n      --help    Show help                                              [boolean]\n  -c, --config  Optional path to gmrc file   [string] [default: .gmrc[.js|.cjs]]\n      --shadow  Apply shadow DB placeholders (for development).\n                                                      [boolean] [default: false]\n```\n\n\n## graphile-migrate run\n\n```\ngraphile-migrate run [file]\n\nCompiles a SQL file, inserting all the placeholders, and then runs it against\nthe database. Useful for seeding. If called from an action will automatically\nrun against the same database (via GM_DBURL envvar) unless --shadow or\n--rootDatabase are supplied.\n\nOptions:\n      --help          Show help                                        [boolean]\n  -c, --config        Optional path to gmrc file\n                                             [string] [default: .gmrc[.js|.cjs]]\n      --shadow        Apply to the shadow database (for development).\n                                                      [boolean] [default: false]\n      --root          Run the file using the root user (but application\n                      database).                      [boolean] [default: false]\n      --rootDatabase  Like --root, but also runs against the root database\n                      rather than application database.\n                                                      [boolean] [default: false]\n```\n\u003c!-- CLI_USAGE_END --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n## Configuration\n\nConfiguration can be stored in a `.gmrc` JSON5 file (compatible with JSON and\n[JSONC](https://code.visualstudio.com/docs/languages/json#_json-with-comments)),\nor in a `.gmrc.js` file which will be `require()`'d. The following configuration\noptions are available:\n\n- `connectionString` (or `DATABASE_URL` envvar) — this is your main development\n  database. If you run `graphile-migrate reset` this will be dropped without\n  warning, so be careful.\n- `shadowConnectionString` (or `SHADOW_DATABASE_URL` envvar) — the shadow\n  database which will be dropped frequently, so don't store anything to it that\n  you care about.\n- `rootConnectionString` (or `ROOT_DATABASE_URL` envvar) — this is used to\n  connect to the database server with superuser (or superuser-like) privileges\n  to drop and re-create the relevant databases (via the `reset` command\n  directly, or via the `commit` command for the shadow database). It **must\n  not** be a connection to the database in `connectionString` or\n  `shadowConnectionString`. It defaults to \"template1\" if the key or environment\n  variable is not set so it may result in PG connection errors if a default PG\n  `template1` database is not available.\n- `pgSettings` — optional string-string key-value object defining settings to\n  set in PostgreSQL when migrating. Useful for setting `search_path` for\n  example. Beware of changing this, a full reset will use the new values which\n  may lead to unexpected consequences.\n- `placeholders` — optional string-string key-value object defining placeholder\n  values to be replaced when encountered in any migration files. Placeholders\n  must begin with a colon and a capital letter, and then can continue with a\n  string of capital letters, numbers and underscores `/^:[A-Z][A-Z0-9_]+$/`.\n  `:DATABASE_NAME` and `:DATABASE_OWNER` are automatically added to this object.\n  The value must be a valid in the place you use it (i.e. ensure you escape the\n  values) — graphile-migrate does not perform any escaping for you. The special\n  value `!ENV` will tell graphile-migrate to load the setting from the\n  environment variable with the same name.\n- `beforeReset` — optional list of actions to execute before deleting and\n  recreating the database.\n- `afterReset` — optional list of actions to execute after the database has been\n  created but before the migrations run, useful to set default permissions,\n  install extensions or install external schemas like `graphile-worker` that\n  your migrations may depend on. See \"Actions\" below.\n- `beforeAllMigrations` — optional list of actions to execute before any pending\n  migrations are executed.\n- `afterAllMigrations` — optional list of actions to execute after all the\n  migrations have ran, useful for performing a tasks like dumping the database\n  or regenerating dependent data (GraphQL schema, type definitions, etc). See\n  \"Actions\" below.\n- `beforeCurrent` — optional list of actions to execute before `current.sql` is\n  executed.\n- `afterCurrent` — optional list of actions to execute after `current.sql` is\n  loaded into the database. See \"Actions\" below.\n- `manageGraphileMigrateSchema` (defaults to `true`) — if set to `false`, you\n  assume responsibility for managing the `graphile_migrate` schema. **Not\n  recommended.** This is useful in environments where the user running the\n  migrations isn't granted schema creation privileges. If you set this to\n  `false`, you must be sure to migrate the `graphile_migrate` database schema\n  any time you update the `graphile-migrate` module.\n- `blankMigrationContent` ─ what should be written to the current migration\n  after commit. NOTE: this should only contain comments such that the current\n  commit is \"empty-ish\" on creation.\n- `migrationsFolder` ─ allows you to override where migrations are stored;\n  defaults to `./migrations`.\n\nWhat follows is an example configuration file that depends on the following\nenvironmental variables being set:\n\n- `ROOT_DATABASE_URL` - equivalent to `rootConnectionString` above, e.g.\n  `postgres://localhost/template1`\n- `DATABASE_URL` - equivalent to `connectionString` above, e.g.\n  `postgres://my_user:my_password@localhost/my_db`\n- `SHADOW_DATABASE_URL` - equivalent to `shadowConnectionString` above, e.g.\n  `postgres://my_user:my_password@localhost/my_db_shadow` (should use same\n  credentials as the )\n\n```json\n{\n  \"pgSettings\": {\n    \"search_path\": \"app_public,app_private,app_hidden,public\"\n  },\n  \"placeholders\": {\n    \":DATABASE_AUTHENTICATOR\": \"!ENV\",\n    \":DATABASE_VISITOR\": \"!ENV\"\n  },\n  \"afterReset\": [\n    \"afterReset.sql\",\n    {\n      \"_\": \"command\",\n      \"command\": \"DATABASE_URL=\\\"$GM_DBURL\\\" npx --no-install graphile-worker --schema-only\"\n    }\n  ],\n  \"afterAllMigrations\": [\n    {\n      \"_\": \"command\",\n      \"command\": \"pg_dump --schema-only --no-owner --exclude-schema=graphile_migrate --file=data/schema.sql \\\"$GM_DBURL\\\"\"\n    }\n  ],\n  \"afterCurrent\": [\"afterCurrent.sql\"]\n}\n```\n\nA `.gmrc.js` configuration file could be identical to the above, except the\nopening brace `{` would be prepended with `module.exports =`:\n\n```js\nmodule.exports = {\n```\n\nAll commands accept an optional `--config` parameter with a custom path to a\n`.gmrc(.js)` file. This is useful if, for example, you have a monorepo or other\nproject with multiple interacting databases.\n\n### Windows\n\nSince committed migrations utilize hashes to verify file integrity, the\ndifference between LF and CRLF line endings on \\*nix and Windows will cause the\nhash verification to fail. Git's default/recommended approach to line endings is\nto convert back and forth depending on your platform. To work around this, we\nrecommend adding a `.gitattributes` file to force LF line endings for the\ncommitted migrations on all platforms:\n\n```\nmigrations/committed/*.sql text eol=lf\nmigrations/current.sql text eol=lf\n```\n\nAfter committing this change, you may run `git checkout-index --force --all` to\nrewrite the working copy with LF line endings. If that command does not replace\nthe CRLF line endings, you may need to delete your copy of the repo and\nre-clone.\n\n## Actions\n\nWe support certain \"actions\" after certain events happen; for example see\n`afterReset`, `afterAllMigrations` and `afterCurrent` mentioned above. Actions\nshould be specified as a list of strings or action spec objects.\n\n### Actions spec strings\n\nString values are converted to `sql` action specs (see below) with the `file`\nproperty set to the string. I.e. they indicate a file within the `migrations`\nfolder to execute against the database.\n\n### Action spec objects\n\nAction spec objects are plain JSON objects with the following properties:\n\n- `_` - specifies the type of object (see supported types below)\n- `shadow` (optional) - if set, must be a boolean; `true` indicates the action\n  should only occur against the shadow DB, `false` indicates that the action\n  should not occur against the shadow DB, unset runs against both databases\n\nEach action spec subtype can have its own properties.\n\n#### `sql` action spec\n\ne.g.\n\n```json\n{\n  \"_\": \"sql\",\n  \"file\": \"install_extensions.sql\",\n  \"root\": false\n}\n```\n\nThe `file` indicates the name of a SQL file in the `migrations/` folder to\nexecute against the database (e.g. to set permissions, load data, install\nextensions, etc).\n\nThe `root` property should be used _with care_, and is only supported by the\n`afterReset` hook (all other hooks will throw an error when it is set). When\n`true`, the file will be run using the superuser role (i.e. the one defined in\n`rootConnectionString`) but with the database name from `connectionString`. This\nis primarily useful for creating extensions.\n\nAn identical effect can be achieved using the shorthand syntax of prepending the\nfile name with an exclamation point, like so:\n\n```json\n\"afterReset\": [ \"!install_extensions.sql\" ]\n```\n\n#### `command` action spec\n\ne.g.\n\n```json\n{\n  \"_\": \"command\",\n  \"command\": \"npx --no-install graphile-worker --once\"\n}\n```\n\n`command` actions specify shell actions (e.g. running an external command such\nas `graphile-worker` which might install a separately managed worker schema into\nthe database, or running something like `pg_dump` to dump the schema).\n\nWhen the command is invoked it will have access to the following envvars:\n\n- `GM_DBURL` - the relevant database URL (e.g. the one that was just\n  reset/migrated)\n- `GM_DBNAME` - the database name in `GM_DBURL`\n- `GM_DBUSER` - the database user in `GM_DBURL` if `root` is `false`.\n- `GM_SHADOW` - set to `1` if we're dealing with the shadow DB, unset otherwise\n\n**IMPORTANT NOTE** the `DATABASE_URL` envvar will be set to the nonsense value\n`postgres://PLEASE:USE@GM_DBURL/INSTEAD` to avoid ambiguity - you almost\ncertainly mean to use `GM_DBURL` in your scripts since they will want to change\nwhichever database was just reset/migrated/etc (which could be the shadow DB).\n\nThe `root` property applies to `command` actions with the similar effects as\n`sql` actions (see above). When `true`, the command will be run with GM_DBURL\nenvvar set using the superuser role (i.e. the one defined in\n`rootConnectionString`) but with the database name from `connectionString`. When\n`root` is true, `GM_DBUSER` is not set.\n\n## Collaboration\n\nThe intention is that developers can work on different migrations in parallel,\nand can switch between `git` branches - idempotent migrations using `CASCADE`\nwhen dropping should make it possible to do this with little issue (other than\nthe implicit data loss of dropping tables/columns/etc).\n\n`graphile-migrate commit`, on the other hand, should be linear - one way to\napproach this is to only commit a migration immediately before it is merged to\n`master`. Another approach is to do the commit on `master` itself. Non-linear\nmigration commits will result in errors, and may lead to you resetting your\ndevelopment database.\n\n## Idempotency\n\n`graphile-migrate` is all about iteration; you write your database modification\ncommands in `migrations/current.sql` and every time you save it is ran against\nthe database, generally taking under 100ms.\n\nBecause we run the same script over and over (on every save) and there's no down\nmigrations, you need to make your script idempotent. PostgreSQL has a number of\nidempotent commands such as:\n\n```sql\ncreate or replace function...\ndrop table if exists ...\ndrop trigger if exists ...\n-- etc\n```\n\nWhen these aren't suitable you can start your migration with an explicit\nrollback: commands that undo later actions. For example:\n\n```sql\n-- undo\ndrop table if exists people;\n\n-- redo\ncreate table people (\n  id serial primary key,\n  name text\n);\n```\n\nWhen it comes time to commit your migration we will run it against a \"shadow\"\ndatabase to make sure it's valid.\n\nIt's often wise to use `DROP ... CASCADE` so that if other migrations are worked\non in parallel no additional `rollback` step is required. When you\n`DROP ... CASCADE`, be sure to add back any dropped dependents (triggers,\nindexes, etc) once the dropped entity has been replaced. Reviewing the database\nschema diff can help you spot these issues.\n\nMore examples of idempotent operations can be found in\n[docs/idempotent-examples.md](./docs/idempotent-examples.md).\n\n## Disable Transaction\n\nSome migrations require execution outside of a transaction (e.g. to enable\naugmenting non-DDL-safe things, such as ENUMs in PostgreSQL). To disable\nwrapping a given migration file in a transaction, use the special comment\n`--! no-transaction` at the top of the migration file, e.g.\n\n```sql\n--! no-transaction\nALTER TYPE user_role ADD VALUE IF NOT EXISTS 'Admin';\n```\n\n**IMPORTANT**: `pg` always runs multi-statement queries in a pseudo-transaction,\nso `--! no-transaction` migrations must contain exactly one statement.\n\n## Editing a committed migration\n\nGraphile Migrate deliberately performs cryptographic hashing to avoid/detect\naccidental editing of committed migrations and to ensure there is a strict\nlinear progression in migrations. By default, Graphile Migrate will refuse to\nrun a migration if its hash does not match what it declares; this is generally\ndesired (and you shouldn't have to worry about it).\n\nShould you need to go back and edit a _committed_ migration you can opt out of\nGraphile Migrate's consistency checks by adding the comment\n`--! AllowInvalidHash` to the very top of the committed migration. Please note\nthat editing the migration **WILL NOT** cause the migration to run again on\nyours or any other system.\n\nThe need to edit a previous migration generally arises if there was a mistake in\nyour migration that prevents it running on production but you don't want to\nreset your staging database, or where an update to PostgreSQL has made the\nsyntax or commands in an older migration invalid and thus you must edit them to\nmake the migration run against a clean database again. Most users should never\nneed this functionality. If you find yourself using it more than once or twice,\nplease get in touch and we can discuss how the tool can better serve your needs.\n\n## Terminology\n\n### The current migration\n\nThe file (or files) in which the non-committed migration that would be executed\nby `graphile-migrate watch` is defined. By default this is in the\n`migrations/current.sql` file, but it might be `migrations/current/*.sql` if\nyou're using folder mode.\n\n#### Including external files in the current migration\n\nYou can include external files in your `current.sql` to better assist in source\ncontrol. These includes are identified by paths within the `migrations/fixtures`\nfolder.\n\nFor example. Given the following directory structure:\n\n```\n/- migrate\n - migrations\n   |\n   - current.sql\n   - fixtures\n     |\n     - functions\n       |\n       - myfunction.sql\n```\n\nand the contents of `myfunction.sql`:\n\n```sql\ncreate or replace function myfunction(a int, b int)\nreturns int as $$\n  select a + b;\n$$ language sql stable;\n```\n\nWhen you make changes to `myfunction.sql`, include it in your current migration\nby adding `--!include functions/myfunction.sql` to your `current.sql` (or any\n`current/*.sql`). This statement doesn't need to be at the top of the file,\nwherever it is will be replaced by the content of\n`migrations/fixtures/functions/myfunction.sql` when the migration is committed.\n\n```sql\n--!include functions/myfunction.sql\ndrop policy if exists access_by_numbers on mytable;\ncreate policy access_by_numbers on mytable for update using (myfunction(4, 2) \u003c 42);\n```\n\nand when the migration is committed or watched, the contents of `myfunction.sql`\nwill be included in the result, such that the following SQL is executed:\n\n```sql\ncreate or replace function myfunction(a int, b int)\nreturns int as $$\n  select a + b;\n$$ language sql stable;\ndrop policy if exists access_by_numbers on mytable;\ncreate policy access_by_numbers on mytable for update using (myfunction(4, 2) \u003c 42);\n```\n\n### Committed migration(s)\n\nThe files for migrations that you've committed with `graphile-migrate commit`\n(note: this is different to committing the files using your version control\nsystem, e.g. git). By default they're located in `migrations/committed/*.sql`\nand are numbered.\n\n### Root\n\nWe use the term \"root\" to indicate a database role with superuser or\nsuperuser-like privileges. This should include the ability to create and delete\ndatabases, but may also include the abilities to create extensions and/or roles.\n\nSince \"superuser\" has a specific meaning and is not strictly required for these\nactivities we avoid that term, however you may find that you use a superuser as\nyour root user - this is expected.\n\n## Status\n\n**STABLE**\n\nThis project is intended to be consumed via the CLI, which is stable and is\nbeing used in production in many projects. The CLI doesn't have explicit tests\n(PR welcome!), but it's a thin wrapper around the programmatic API which has\ncopious tests.\n\nThe programmatic API is deliberately undocumented; it is not a public interface\nat this time (though it is fully typed in TypeScript). We reserve the right to\nmake breaking changes to the programmatic API in patch releases (though this has\nnot happened yet and is unlikely to happen without good reason). Should you need\nto use the programmatic API, please get in touch to encourage us to make this a\nsupported interface ─ we'd love to know how you're using it!\n[src/cli.ts](src/cli.ts) is the best place to start.\n\nThe project as a whole is stable, but the approach is still \"experimental\", in\nparticular:\n\n- the approach of up-only and re-runnable migrations is not for the faint of\n  heart ─ it requires solid SQL knowledge and if insufficient attention is paid\n  it could result in your migrations and your local database state drifting\n  apart (see 'Drift' below).\n\nIf you don't understand what makes Graphile Migrate awesome, you may want to\nconsider an alternative migration framework such as these awesome (and quite\ndiverse) projects:\n\n- [db-migrate](https://db-migrate.readthedocs.io/en/latest/Getting%20Started/commands/)\n- [sqitch](https://sqitch.org/)\n- [Flyway](https://flywaydb.org/)\n- [migra](https://github.com/djrobstep/migra)\n\n## Node.js versioning policy\n\nWe only support LTS versions of Node.js; the currently supported versions are:\n\n- Node v14.x\n- Node v16.x\n- Node v18.x\n\nOther versions of Node may work, but are not officially supported.\n\nOnce a Node.js version becomes \"unsupported\" (i.e. the maintenance LTS window\nends), this project will no longer support it either. We may drop support for\nunmaintained versions of Node.js in a **minor** release.\n\n## Drift\n\n\u003e **NOTE**: drift only affects your local development database, it cannot occur\n\u003e in your production database assuming you're only using\n\u003e `graphile-migrate migrate` in production.\n\nIn development, if you're insufficiently careful with modifications to\n`current.sql` (including when you choose to save the file, and when switching\nbranches in `git`) you may end up with a local database state that differs from\nwhat you'd expect given the committed migrations and contents of `current.sql`.\nWe **strongly recommend against auto-save** for this reason; and recommend that\nyou keep a dumped `schema.sql` to help you spot unexpected changes.\n\nHere's an illustrative example to explain the drift phenomenon, with function\ninspired by [XKCD221](https://xkcd.com/221/). Imagine that you're running\n`graphile-migrate watch` locally and you write the following to `current.sql`:\n\n```sql\n-- Revision 1\ncreate function rnd() returns int as $$\n  select 4;\n$$ language sql stable;\n```\n\nBecause `watch` runs the contents of `current.sql` whenever it changes, this\nwill create the `rnd()` function in your local database.\n\nA couple seconds later you change your mind, and decide to rename the function,\nwriting the following to `current.sql`:\n\n```sql\n-- Revision 2\ncreate function get_random_number() returns int as $$\n  select 4;\n$$ language sql stable;\n```\n\nThis creates `get_random_number()`, but no-one ever said to delete `rnd()`, so\nnow both functions exist. According to the committed migrations and\n`current.sql` only `get_random_number()` should exist. The existence of the\norphaned `rnd()` function in your local database is what we term \"drift\" ─ this\nfunction will never appear in your production database even after you commit\nthis latest migration; it also won't be in your shadow database (because we\nreset the shadow database and reapply all the migrations frequently).\n\nSince Graphile Migrate doesn't know how to reverse the SQL you've written, it's\nup to you to make the SQL safe so that it can be ran over and over, and adjust\nto your changes. The two to `current.sql` versions above should have been\n\n```sql\n-- Revision 1\ndrop function if exists rnd();\n\ncreate function rnd() returns int as $$\n  select 4;\n$$ language sql stable;\n```\n\nand\n\n```sql\n-- Revision 2\ndrop function if exists rnd();\ndrop function if exists get_random_number();\n\ncreate function get_random_number() returns int as $$\n  select 4;\n$$ language sql stable;\n```\n\n## Using Migrate with an existing database\n\nYou can use Graphile Migrate to manage the migrations for your existing system,\nbut the process is slightly different.\n\nBecause Graphile Migrate tracks which migrations it has ran and runs remaining\nmigrations, you must not put your existing database schema as the first\nmigration otherwise you production database might be wiped (or it just won't\nwork) when Graphile Migrate attempts to apply it. Instead you must ensure all\ndatabases (development, staging, production, etc.) are at the same state before\nrunning any migrations, and then the Graphile Migrate migrations will be applied\n_on top_ of this initial state.\n\n### Storing the initial state\n\nThough you could hand-roll the initial state if you prefer, we generally advise\nthat you take a schema-only dump of your existing (production) database schema\nand store it to `migrations/initial_schema.sql` with a command such as:\n\n```\npg_dump --schema-only --no-owner --file=migrations/initial_schema.sql \"postgres://...\"\n```\n\nIf you manage some of the data in your initial database schema using your\nexisting migration system then you should add that data to your\n`initial_schema.sql` file too.\n\n### New databases must apply the initial state\n\nWhen creating new databases (e.g. test databases, new development databases for\nnew developers, when resetting your development database, whenever Graphile\nMigrate recreates the shadow database, etc.) it's imperative that these new\ndatabases also have `initial_schema.sql` applied to them.\n\n#### Applying the initial schema with Actions\n\nOne way to apply the initial schema is to use [Actions](#actions), specifically\nthe `afterReset` action, to apply the initial schema immediately after the\ndatabase is reset/created and before any committed migrations are applied. Add\nsomething like `\"afterReset\": [ \"initial_schema.sql\" ]` to your `.gmrc` and\nwhenever Graphile Migrate's `reset` command runs (including against the shadow\ndatabase when committing a migration) this initial schema will be applied. Note\nthis is only used when a DB is reset (i.e. when you have Graphile Migrate create\nit) and thus it won't be a concern for production since you never run `reset`\nthere.\n\n#### Applying the initial schema in other ways\n\nYou can take care of applying the initial schema using your own tooling should\nyou want or need to do so.\n\nThe [official PostgreSQL Docker container](https://hub.docker.com/_/postgres)\nhas the `/docker-entrypoint-initdb.d/` directory for initialization scripts, and\nthis might be a good location for your `initial_schema.sql` file if you're using\nthis image.\n\n**Important note**: in development the shadow database must be able to be\ndestroyed and recreated by Graphile Migrate at will, so applying the initial\nschema _to the shadow database_ must be done via an Action (see above). You can,\nhowever, ensure that your action only applies to the shadow database by setting\nthe `\"shadow\": true` property, leaving you free to manage how your more\npermanent databases are initialized.\n\n## Examples\n\n- [Running Graphile Migrate in a Docker container](docs/docker/README.md)\n- [Examples of idempotent migration files including edge cases](docs/idempotent-examples.md)\n\n## TODO:\n\n- [ ] Store pgSettings with committed transactions to protect against user edits\n\n- [ ] Add `graphile-migrate check` command: reset the shadow database to the\n      latest dump, apply the current migration to the shadow database, and\n      output a SQL schema diff you can use to ensure no accidental changes have\n      been made\n\n- [ ] Add `graphile-migrate import` command: used after init but before running\n      any other commands, imports the existing database as if it were the first\n      migration. (For now, see\n      [Using Migrate with an existing database](#using-migrate-with-an-existing-database).)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphile%2Fmigrate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphile%2Fmigrate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphile%2Fmigrate/lists"}