CLI tool
shayonj/pg_easy_replicate avatar
shayonj/pg_easy_replicate

shayonj/pg_easy_replicate: a Ruby orchestrator for PostgreSQL logical replication and low downtime switchover

Easily setup logical replication and switchover to new database with minimal downtime

1,040 stars23 forksRubyMIT

At a glance

What is it?
pg_easy_replicate is a MIT licensed command line tool that sets up logical replication between two PostgreSQL databases and then performs a switchover, putting the source into read-only mode and flushing the remaining data across so the changeover has no data loss and minimal application downtime. It is used in production at Tines, and it does the tedious parts of replication setup that the PostgreSQL documentation leaves as an exercise.
Who is it for?
Adopt pg_easy_replicate if you move a PostgreSQL database regularly, whether for a major version upgrade, a Blue and Green cutover or a load test, since it automates the publication, subscription, bootstrap and flush steps that make logical replication usable in practice.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 88 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the tool actually does

pg_easy_replicate is a CLI orchestrator tool that simplifies the process of setting up logical replication between two PostgreSQL databases, and it also supports switchover.

The switchover is the part that explains why the tool exists. After the source, the primary database, is fully replicated, pg_easy_replicate puts it into read-only mode and, via logical replication, flushes all data to the new target database. The stated result is zero data loss and minimal downtime for the application, and the use cases given are minimal downtime, under a minute depending on the circumstances, major version upgrades between a Blue and Green PostgreSQL setup, load testing and similar situations.

That is a specific and well-chosen scope. Setting up logical replication by hand is a dozen `CREATE PUBLICATION` and `CREATE SUBSCRIPTION` statements plus a lot of careful ordering, and doing it repeatedly by hand during a migration window is where mistakes happen. Wrapping that in a tool with a group model and a documented command sequence is the whole value proposition, and the project says it is battle tested in production at Tines, which is a better production reference than most open source tools can offer.

The implementation is a Ruby gem rather than a service or a language extension, and the tool is invoked as a series of discrete commands, so it fits into a runbook rather than into a deployment.

Nine commands and a group name

The command surface is small and every command is scoped to a group, which is the unit of isolation for one replication.

bash
$  pg_easy_replicate
pg_easy_replicate commands:
  pg_easy_replicate bootstrap -g, --group-name=GROUP_NAME    # Sets up temporary tables for information required during runtime
  pg_easy_replicate cleanup -g, --group-name=GROUP_NAME      # Cleans up all bootstrapped data for the respective group
  pg_easy_replicate config_check                             # Prints if source and target database have the required config
  pg_easy_replicate help [COMMAND]                           # Describe available commands or one specific command
  pg_easy_replicate start_sync -g, --group-name=GROUP_NAME   # Starts the logical replication from source database to target database provisioned in the group
  pg_easy_replicate stats  -g, --group-name=GROUP_NAME       # Prints the statistics in JSON for the group
  pg_easy_replicate notify  -g, --group-name=GROUP_NAME,  -u --url=URL_TO_NOTIFY    # Sends notifications of all stats values for a group to a specified url
  pg_easy_replicate stop_sync -g, --group-name=GROUP_NAME    # Stop the logical replication from source database to target database provisioned in the group
  pg_easy_replicate switchover  -g, --group-name=GROUP_NAME  # Puts the source database in read only mode after all the data is flushed and written
  pg_easy_replicate version                                  # Prints the version

The sequence the commands imply is the migration procedure. `config_check` first, which prints whether the source and target databases have the required configuration, and which the README shows succeeding with a check mark and the message that the config is looking good. Then `bootstrap`, which sets up the temporary tables needed for the rest of the process. Then `start_sync` to begin replication. Then `stats` for the JSON statistics, and `notify` to push those statistics to a URL, which is how a changeover can be watched from a monitoring system or a chat channel rather than by watching a terminal. Then `stop_sync` and `switchover`, and finally `cleanup` to remove the bootstrapped data for that group.

The group model is what makes that safe to repeat. You can create as many groups as you want for a single database, and the groups are just a logical isolation of a single replication, so a rehearsal run in one group does not collide with the real one in another.

Configuration is two URLs and two environment variables

The tool is configured entirely through the environment, and the two required variables are the source and the target connection strings.

bash
$ export SOURCE_DB_URL="postgres://USERNAME:PASSWORD@localhost:5432/DATABASE_NAME"
$ export TARGET_DB_URL="postgres://USERNAME:PASSWORD@localhost:5433/DATABASE_NAME"

`SOURCE_DB_URL` is the database you replicate from and `TARGET_DB_URL` is the database you replicate to, and the URL is in PostgreSQL connection string format. There is no configuration file, which is the right choice for a tool that runs inside a migration script.

Two optional variables tune the behaviour. `PG_EASY_REPLICATE_STATEMENT_TIMEOUT` extends the default timeout of five seconds, and `DEBUG="true"` turns on additional debug logging. The timeout matters more than it looks, because replication setup involves waiting for the target to catch up, and a five second default is a short leash on a large table.

The Docker route passes the same variables straight through, and the README gives the pattern:

bash
docker run -e SOURCE_DB_URL="postgres://USERNAME:PASSWORD@localhost:5432/DATABASE_NAME"  \
  -e TARGET_DB_URL="postgres://USERNAME:PASSWORD@localhost:5433/DATABASE_NAME" \
  -it --rm shayonj/pg_easy_replicate:latest \
  pg_easy_replicate config_check

The only requirement stated is that the container has access to both databases, which is why the image is built for exactly this shape of one off invocation rather than as a long running service.

Permissions, and the role the tool creates for itself

The requirements are PostgreSQL 10 and later, Ruby 3.0 and later, and a database user with `SUPERUSER` permissions, or a special user with privileges to create the needed role, schema, publication and subscription on both databases.

That second option is the one worth understanding, and the README has a section for it, covering bootstrap and config check with a special user role in AWS or GCP. The point is that in a managed cloud database, handing your application a superuser is usually impossible and often forbidden, and a tool that needs one will simply not run. The `--special-user-role` option exists so the orchestration can be done by a role with only the specific privileges required, which is what a cloud deployment needs.

The bootstrap command is where that role comes from. Every sync needs to be bootstrapped before the sync can be set up, and bootstrap creates a new super user to perform the orchestration required during the rest of the process, and it also creates some internal metadata tables for record keeping. The example shows the call with a group name and a copy schema flag, and the output is the tool's own structured log lines, in JSON, carrying a name, a hostname, a pid, a level and a message.

The FAQ covers the other half of the permission problem, how to add the internal user to `pg_hba` or to a pgBouncer `userlist`, which is the usual failure mode when a pooled connection layer sits between the tool and the database.

DDL changes, and the two switchover strategies

Two sections in the table of contents describe what a logical replication setup does not give you for free.

The first is DDL changes management, split into listing DDL changes and applying DDL changes. This exists because logical replication in PostgreSQL replicates data, not schema, so a table altered on the source is not altered on the target, and the tool provides a way to find the differences and apply them. It is the part of the operational surface that a team discovers during its first migration if nobody read the documentation, and having a command for it is the difference between a repeatable process and a manual diff.

The second is the switchover strategy, and there are two of them, chosen by what your application can tolerate. The rolling restart strategy restarts the application instances one at a time so that the client connections migrate gradually, and the DNS failover strategy changes where the hostname resolves and relies on the client to reconnect. The choice depends on whether your clients can be pointed somewhere else, and the downtime claim of under a minute depends on which one you use and how much data is still in flight.

The other utility commands round out the tool. `stats` prints the replication statistics as JSON for the group, which is what a monitoring system consumes, and `notify` sends those statistics to a URL, so an automated cutover can watch for lag and act.

Where this is the wrong tool

The first wrong case is failover. pg_easy_replicate orchestrates a planned changeover, and the read-only and flush sequence assumes someone is watching. Automatic failover, with a standby that takes over when the primary disappears, is a different problem with different tooling, and the logical replication restrictions in the PostgreSQL documentation apply to both.

The second is a database where you need continuous replication. The tool is built around a sequence of commands you run at a point in time, not a daemon that keeps a replica in sync continuously, and treating it as the latter will produce surprises.

The third is a schema-heavy workload with constant DDL. The DDL change management commands exist, which tells you the problem is real and that the answer is a process rather than an absence of one, and a team that changes schema daily will spend more time in that section than in the rest of the tool.

The fourth is an environment where the database user cannot be given the privileges it needs. Even with the special user role option, there are managed setups where creating a publication or a subscription is not permitted, and then the tool is not usable at all.

On the state of the project, the releases are v0.3.6 from 2024-11-22, v0.3.8 from 2024-12-08 and v0.4.0 from 2025-10-27, and the last push to the repository was on 2026-07-27 with the repository not archived. The licence is MIT, the gem is `pg_easy_replicate`, and the tree is a conventional Ruby project with `lib/`, `bin/`, `spec/` and a `Rakefile`. The development setup is a compose file with a source database on PostgreSQL 14 and a target on PostgreSQL 12, both with `wal_level=logical` and SSL enabled, which is the detail that makes the two different major versions in the fixture a deliberate test rather than an accident. The Dockerfile is on `ruby:3.4.4-slim` and installs the PostgreSQL client and the published gem at a pinned version.

Editorial conclusion

Adopt pg_easy_replicate if you move a PostgreSQL database regularly, whether for a major version upgrade, a Blue and Green cutover or a load test, since it automates the publication, subscription, bootstrap and flush steps that make logical replication usable in practice. Do not adopt it expecting replication to be a substitute for a failover system, because it is an orchestration tool for planned changeovers and the underlying logical replication restrictions still apply, including that DDL is not replicated for you. Verify first that both databases run PostgreSQL 10 or later with logical WAL enabled, that the credentials can create the roles, schemas, publications and subscriptions needed on both ends or that you use the special user role option, and that your clients can be pointed at a different endpoint, since the switchover strategies are rolling restart and DNS failover.

Frequently asked questions

What does pg_easy_replicate do?

It is a CLI orchestrator that sets up logical replication between two PostgreSQL databases and supports switchover, putting the source into read-only mode and flushing the remaining data to the target so the changeover has zero data loss and minimal downtime. The stated use cases are major version upgrades in a Blue and Green setup and load testing.

How do I configure and run pg_easy_replicate?

Export `SOURCE_DB_URL` and `TARGET_DB_URL` as PostgreSQL connection strings, optionally set `PG_EASY_REPLICATE_STATEMENT_TIMEOUT` to extend the five second default and `DEBUG=true` for more logging, then run the commands in order: config_check, bootstrap, start_sync, stats, and then stop_sync and switchover, with cleanup at the end.

What permissions does pg_easy_replicate need?

Either a user with SUPERUSER permissions, or a special user with privileges to create the needed role, schema, publication and subscription on both databases, which is the option the README describes for AWS or GCP. The FAQ also covers adding the internal user to `pg_hba` or to a pgBouncer `userlist`.

What are the groups in pg_easy_replicate?

They are a logical isolation of a single replication, and you can create as many groups as you want for one database. Every command except config_check and version takes a group name, and bootstrap creates the metadata tables and the orchestration user for that group while cleanup removes them.

How does pg_easy_replicate handle schema changes?

Through a DDL changes management section of the documentation, with one command to list DDL changes and another to apply them, because logical replication in PostgreSQL replicates data rather than schema. The switchover strategy is chosen separately, as a rolling restart of application instances or a DNS failover.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. shayonj/pg_easy_replicate on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/shayonj-pg-easy-replicate.svg)](https://hysenlabs.com/projects/shayonj-pg-easy-replicate)

Was this useful?