pglogrepl is a thin Go layer over the PostgreSQL replication protocol
PostgreSQL logical replication library for Go.
At a glance
- What is it?
- pglogrepl is a Go package for PostgreSQL logical replication that sits on top of pgx's pgconn and adds the message decoding, so you can read the replication stream as typed Go structs rather than raw bytes. It also carries the physical replication example, and its own test setup asks you to change wal_level and open pg_hba.conf.
- Who is it for?
- Adopt pglogrepl if you are writing a Go program that needs to consume a PostgreSQL replication stream, whether logical replication for change data capture or physical replication for a replica, because it gives you decoded message structs over an existing pgx connection instead of a protocol implementation you would write yourself.
- 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 20 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the package actually is, and what it deliberately is not
pglogrepl is described in one line as a Go package for PostgreSQL logical replication, and the README then says something that tells you where to look for the difficulty: proper use of this package requires understanding the underlying PostgreSQL concepts, with a link to the protocol replication documentation.
That sentence is the design statement. This is not a library that hides replication behind a friendly API. It is a decoder.
The layer it adds is narrow and specific. pglogrepl uses github.com/jackc/pgx/v5/pgconn as its underlying PostgreSQL connection, so the transport, the authentication and the connection handling come from pgx, and what pglogrepl adds is the knowledge of the replication protocol's message formats. The top-level files show the split: pglogrepl.go holds the client, message.go and messageV2.go hold the message definitions in two protocol generations, and each has a corresponding test file.
The two message files are the part worth understanding. A logical replication connection in PostgreSQL runs over the normal protocol but switches into replication mode, where the server sends a stream of XLogData messages rather than query results. Each of those carries a logical replication message: a begin, a commit, a relation describing a table's schema, an insert, an update, a delete, a truncate, a type, an origin, and the metadata messages that carry the logical replication message types and the streaming state. Decoding those into Go structs is the work, and doing it twice, for message version 1 and version 2, is what the two files are.
The version split is not something the package invents. PostgreSQL has two logical replication message protocols and the server tells the client which one it speaks during the handshake, so a client that wants to work across server versions has to carry both. The Go module requires Go 1.25.0, depends on pgx v5.9.1, pgio v1.0.0 for the binary encoding, and testify for the tests.
The licence is MIT, the default branch is master, the last push was on 2026-10-03, and there are no GitHub releases, so you depend on a commit rather than a tag.
Two example programs, one logical and one physical
The example directory holds two demo programs, and the distinction between them maps onto the two replication modes PostgreSQL offers.
In example/pglogrepl_demo there is a program that connects to a database and logs all messages sent over logical replication. In example/pgphysrepl_demo there is a program that connects to a database and logs all messages sent over physical replication.
Both are described the same way, as logging all messages, and that symmetry is deliberate. The two modes carry different payloads on the wire but share the same envelope, so a decoder for the replication protocol can be exercised against either.
Logical replication is the one most people mean when they say replication to a Go program. The server streams row-level changes for tables in published publications, which is what you want for change data capture, for building a search index, or for replicating selected tables to another system. The messages describe changes: an insert carries the new row's values, an update carries the old key and the new values, a delete carries the old key.
Physical replication is the server streaming write-ahead log segments, the same bytes a standby server would apply. The messages there are not row changes but the WAL data itself, and the receiver's job is to write it to disk in the right place rather than interpret it. That is a much lower-level thing to be doing from Go, and the reason the example is worth having is that it shows the decoding layer handling that case too.
Neither example is described as a production component. They log messages, which is exactly what you want when you are learning the protocol or checking what your server is actually sending. The library's own README does not document a consumer API in detail, which suggests the intended usage is that you read the message types in the source and write the handling you need, using the examples as the reference for how a connection is set up.
The reference to the protocol replication documentation in the README is doing real work here. Anyone writing a consumer needs to know what the server sends and in what order, and that document is the specification the package implements rather than a supplement to it.
The test setup tells you what the library needs from a server
The testing section is the most informative part of the README for someone deciding whether to use this package, because it enumerates the server-side requirements exactly.
Testing requires a user with replication permission, a database to replicate, access allowed in pg_hba.conf, and logical replication enabled in postgresql.conf. Four requirements, each of which corresponds to something you have to change on the server.
The setup is SQL and configuration, in that order. You create the database:
create database pglogrepl;And the user, with the replication attribute and a password:
create user pglogrepl with replication password 'secret';Then, if you are on PostgreSQL 15 or newer, you grant access to the public schema, just for these tests:
grant all on schema public to pglogrepl;The pg_hba.conf line that permits the connection over TCP is:
host replication pglogrepl 127.0.0.1/32 md5And the three postgresql.conf settings that turn on the machinery:
wal_level=logical
max_wal_senders=5
max_replication_slots=5That last block is the one that matters most in practice. wal_level=logical is what makes the server emit logical replication messages at all, and it is a setting that requires a restart and that most servers are not running with, because it costs write-ahead log volume for a server that is not replicating. max_wal_senders and max_replication_slots are both 5 here, and both need to be at least as large as the number of concurrent replication connections, with the slot count also bounded by the number of subscriptions or consumers you want running.
The order of those settings is also a practical detail. wal_level has to be set before the server starts, or before it is restarted, so it is not a change you can make and see take effect immediately like a per-role setting.
The connection string then has to be a replication connection string, which the README describes as a URL or DSN, and the example shows the shape:
PGLOGREPL_TEST_CONN_STRING=postgres://pglogrepl:[email protected]/pglogrepl?replication=database go testThe replication=database parameter in the URL is what makes libpq enter replication mode rather than normal session mode, and getting it wrong produces a connection that connects fine and then cannot start replication. That single query parameter is the thing to copy exactly.
The base backup test, and the flag that disables it
One of the tests does something the others do not, and the README explains why and how to turn it off.
Since the base backup would request postgres to create a backup tar and stream it, this test can be disabled with an environment variable:
PGLOGREPL_SKIP_BASE_BACKUP=trueA base backup is the initial copy of the database that a physical replica starts from before it begins streaming WAL. It is a heavyweight operation, it produces a tarball the server streams over the replication connection, and it needs the replication user to have the right attributes and the server to have the disk space and the basebackup target configured.
For a test suite that means the base backup test is the slowest and most environment-dependent test in the package, because it depends on server-side state that the test setup does not create. The docker-compose.yml in the repository root is the workaround: it runs postgres with the image postgres:${POSTGRES_VERSION:-17}-alpine, in host network mode, with the POSTGRES_COMMAND variable carrying the server command including the wal_level, max_wal_senders and max_replication_slots flags as inline -c arguments.
The defaults in that compose file match the test setup: the user is pglogrepl, the password is secret, the database is pglogrepl, and POSTGRES_HOST_AUTH_METHOD is trust, which means the local container accepts any password. That is fine for a throwaway test container and would be wrong anywhere else.
The POSTGRES_COMMAND variable being a required environment variable rather than a default is a small detail that tells you the compose file expects you to supply the server flags, and the commented-out example shows what goes in it. The image tag defaults to PostgreSQL 17, which is a reasonable current version to test against, and the ${POSTGRES_VERSION:-17} form lets you pin it back if a behaviour differs.
So the test story is: a compose file that starts a server configured for logical replication, a SQL and configuration setup for the database and user, and an environment variable carrying the replication connection string. There is also a second environment variable for skipping the base backup, which is the escape hatch for anyone whose server cannot do it.
Where pglogrepl is the wrong dependency
Three limits, and the first is about how much of the protocol you have to understand.
The first is that the README tells you plainly that proper use requires understanding the underlying PostgreSQL concepts, and it links the protocol replication documentation for that reason. There is no query builder here, no change stream abstraction, no cursor you can page through, no helper for resolving a relation message to your table struct. What you get is decoded messages and the specification to read alongside them. That is a fine library for an engineer who wants to build a change data capture tool, and a poor fit for an application team that wants a subscription API.
The second is that logical replication has prerequisites that are not obvious from the library side. The server must be running with wal_level=logical, which costs write-ahead log volume and needs a restart. A replication slot must exist, and slots hold WAL indefinitely if the consumer falls behind, which is how a database runs out of disk space because a Go program was not running. max_replication_slots and max_wal_senders both cap how many consumers you can have. And the relation messages describe table schemas as the server sees them, so your consumer has to track schema changes over time if tables are altered. None of that is pglogrepl's problem, but all of it is pglogrepl's user's problem.
The third is the release situation. There are no GitHub releases, so there is no tag to pin and no changelog to read. The module requires Go 1.25.0, which is a recent toolchain floor, and pgx v5.9.1 is a moving dependency of a package whose own version is unversioned. For a library that sits close to the wire protocol, that means your upgrade risk is the combination of the PostgreSQL version you run, the pgx version you resolve, and an upstream commit.
The alternative approach for most teams is not to write a replication consumer at all. If you want a replica, PostgreSQL's own streaming replication and logical replication do it. If you want change data capture into a search index or a data warehouse, Debezium and similar connector projects do it, with schema handling, snapshot and offset management included. The difference in approach is that a connector project gives you a running pipeline and takes care of the parts that are genuinely hard, like schema evolution and exactly-once delivery, whereas pglogrepl gives you the decoded bytes and leaves you to build the pipeline, which is the right trade only when you need control over the consumer that a connector does not give you, such as writing to a system that has no connector, or embedding the consumer inside an existing Go service rather than running a separate platform.
Editorial conclusion
Adopt pglogrepl if you are writing a Go program that needs to consume a PostgreSQL replication stream, whether logical replication for change data capture or physical replication for a replica, because it gives you decoded message structs over an existing pgx connection instead of a protocol implementation you would write yourself. Do not adopt it if you only need to replicate a database, since PostgreSQL does that on its own, and do not expect a high-level framework, because the README is candid that proper use requires understanding the underlying PostgreSQL replication concepts. Verify first that your connection string uses the replication parameter in the documented form, that wal_level is set to logical with enough max_wal_senders and max_replication_slots, that the replication user is granted access in pg_hba.conf, and that the PostgreSQL version you run matches the protocol generation your client code handles.
Frequently asked questions
What is pglogrepl and what does it depend on?
It is a Go package for PostgreSQL logical replication that uses github.com/jackc/pgx/v5/pgconn as its underlying PostgreSQL connection and adds the decoding of the replication protocol messages. The module requires Go 1.25.0, pgx v5.9.1, pgio v1.0.0 and testify for the tests.
What server configuration does pglogrepl need for logical replication?
wal_level must be set to logical, and max_wal_senders and max_replication_slots must be raised to cover your consumers, with the README's example using 5 for each. The replication user also needs the replication attribute, and a host replication line in pg_hba.conf permitting the connection.
How do I run the pglogrepl tests?
Create the database and the replication user, grant access to the public schema on PostgreSQL 15 or newer, add the pg_hba.conf replication line, set the postgresql.conf values, then set PGLOGREPL_TEST_CONN_STRING to a replication connection string and run go test. The docker-compose.yml in the repository starts a server with the right flags.
What connection string do the pglogrepl tests use?
The example is PGLOGREPL_TEST_CONN_STRING=postgres://pglogrepl:[email protected]/pglogrepl?replication=database, and the README notes the variable takes a URL or a DSN. The replication=database parameter is what puts the connection into replication mode.
What does the pglogrepl repository include as examples?
Two demo programs: example/pglogrepl_demo connects to a database and logs all messages sent over logical replication, and example/pgphysrepl_demo does the same for physical replication.
Can I skip the base backup test in pglogrepl?
Yes. The base backup test requests that PostgreSQL create a backup tar and stream it, and the README says it can be disabled with PGLOGREPL_SKIP_BASE_BACKUP=true.
Official sources
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.
[](https://hysenlabs.com/projects/jackc-pglogrepl)Was this useful?