wal2json: PostgreSQL Logical Decoding as JSON
JSON output plugin for changeset extraction
At a glance
- What is it?
- wal2json is a C output plugin that converts PostgreSQL logical decoding changes into JSON for consumers using logical replication slots or a SQL API. It suits applications that need row changes as structured data, but PostgreSQL configuration, replica identity, and plugin loading rules impose real constraints.
- Who is it for?
- Engineers should consider wal2json when a PostgreSQL integration needs row-level changes as JSON and its transaction boundary and metadata options fit the consumer. Operators should not choose it for an unsupported PostgreSQL platform or a workload that requires unchanged or old rows without checking replica identity first.
- Can I use it commercially?
- Yes. BSD-3-Clause 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 14 days ago.
- What is it written in?
- Mainly C, 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
Why wal2json Exists in a PostgreSQL Pipeline
wal2json addresses a narrow but consequential gap between PostgreSQL logical decoding and software that expects ordinary JSON. Logical decoding gives an output plugin access to tuples produced by `INSERT` and `UPDATE`. Access to old row versions for `UPDATE` and `DELETE` depends on the configured replica identity. wal2json translates that decoded change stream into JSON, making it suitable for replication consumers, search indexers, cache invalidation services, or custom data pipelines that do not parse PostgreSQL's native logical replication protocol directly.
The project is not a general PostgreSQL driver and does not stand between an application and the database in the usual request-response path. Its scope starts after PostgreSQL has enabled logical decoding and a consumer is reading a logical replication slot or using the plugin's special SQL API. The repository describes C as its primary language and places its implementation in `wal2json.c`.
That boundary matters when comparing designs. A consumer that already handles PostgreSQL replication semantics may prefer native logical replication. wal2json becomes useful when the desired contract is JSON, particularly when transaction grouping, schema names, SQL data types, column positions, primary keys, and transaction markers are useful to the receiving system.
Format Version 1 Transactions Versus Format Version 2 Tuples
The central design choice is the output granularity. Format version 1 produces one JSON object per transaction, with new and old tuples available in that object. This shape maps naturally to consumers that need to process a commit as a unit. The `write-in-chunks` option changes its emission behavior by writing after every change instead of every changeset, but that option is restricted to format version 1.
Format version 2 produces one JSON object per tuple. It can also emit optional JSON objects marking the beginning and end of a transaction. This representation is closer to an event stream and can reduce the need to buffer an entire transaction before forwarding individual row changes. However, transaction structure must still be interpreted correctly when `include-transaction` is enabled.
Metadata is configurable rather than fixed. Defaults include schemas, data types, and type modifiers. Transaction IDs, timestamps, type OIDs, column positions, origins, not-null information, defaults, primary keys, and the next log sequence number can be added. `numeric-data-types-as-string` addresses JSON interoperability involving numeric values such as `Infinity` and `NaN`, while `pretty-print` changes whitespace rather than the decoded change semantics.
The README excerpt does not provide complete schemas for both output formats. An implementation team should therefore treat format selection as an integration decision tied to its consumer, not choose it from the short descriptions alone.
Installing wal2json 2.7 on PostgreSQL 18
The README gives package installation as the shortest first route on Red Hat, CentOS, Debian, and Ubuntu. These commands install packages tied to PostgreSQL 18. The named packages should be used only when the target PostgreSQL major version matches.
For Red Hat or CentOS:
sudo yum install wal2json_18For Debian or Ubuntu:
sudo apt-get install postgresql-18-wal2jsonAfter installation, the server must be configured before a consumer can load wal2json. The README requires `wal_level = logical` in `postgresql.conf` and states that a restart is required after changing that setting. Add these values under `postgresql.conf`:
wal_level = logical
output_plugin_libraries = 'pgoutput, test_decoding, wal2json'The library name in `output_plugin_libraries` must be exactly `wal2json`. Since PostgreSQL 18.6, 17.11, 16.15, 15.19, and 14.24, the README states that an output plugin can load only when its library appears in this parameter. The parameter is read when the plugin loads, so the documented reload mechanisms are sufficient:
pg_ctl reloadThe README excerpt does not include a first slot-creation command or a complete consumer configuration. A real first replication read therefore cannot be reproduced from the documented commands alone without consulting PostgreSQL's own instructions for the selected major version.
Building wal2json Against a Chosen PostgreSQL Prefix
Source builds matter when the operating-system package does not match the PostgreSQL installation or when an operator needs the release's current code. The README says PostgreSQL 10 or later, including headers, must be installed. Its development package examples cover PostgreSQL 18.
For a self-built PostgreSQL installation under `$HOME/pg18`, the documented build flow is:
tar -zxf wal2json-wal2json_2_7.tar.gz
cd wal2json-wal2json_2_7
export PATH=$HOME/pg18/bin:$PATH
make
make installThe `PATH` assignment matters because the repository `Makefile` calls `pg_config` and includes the PostgreSQL extension build system obtained through `pg_config --pgxs`. If `pg_config` resolves to the wrong major release, the build can target a different PostgreSQL installation than the server being configured.
The apt variant uses the package-provided development files:
sudo apt-get install postgresql-server-dev-18
tar -zxf wal2json-wal2json_2_7.tar.gz
cd wal2json-wal2json_2_7
export PATH=/usr/lib/postgresql/18/bin:$PATH
make
make installFor Windows, the README documents either adding the directory to PostgreSQL's `contrib` build or editing `wal2json.vcxproj` so `c:\pg\18` matches the PostgreSQL prefix. It then requires compilation in Microsoft Visual Studio and copying `wal2json.dll` into the directory reported by `pg_config --pkglibdir`.
Replica Identity and Option Boundaries
The most important functional limitation is not JSON rendering. It is how PostgreSQL logical decoding represents row changes. wal2json can expose old tuple values only when the relevant old row version is available under the table's replica identity configuration. A consumer that assumes every `UPDATE` or `DELETE` always contains complete before-state data can therefore build the wrong contract.
The plugin offers precise controls, but each one affects output size or decoding effort. Enabling schema and type metadata can make events easier to interpret, while primary-key output, type OIDs, origins, defaults, and column positions add fields that an integration may not need. Transaction IDs, timestamps, and LSNs answer different operational questions and should not be enabled merely because the options exist.
Empty transactions expose another boundary. `include-empty-transaction` can emit transactions without changes, including DDL-only transactions or transactions whose changes were all filtered out. If it is false, a transaction start record is emitted only before the first change. With format version 2 and `include-transaction` disabled, a transaction without changes produces no output. Consumers must distinguish absence of output from an ordinary row-change event.
There are also PostgreSQL-version differences. The repository `Makefile` omits the `truncate` regression test on PostgreSQL 10, while the `actions` API test is also removed for that version. Partitioned-table coverage in `include_empty_transaction` requires PostgreSQL 11 or later. The SQL API and expected regression behavior therefore need to be checked against the server version being used.
Maintenance, License, and Upgrade Surface
The repository is not archived, and the last push was on 2026-10-09. Release `wal2json_2_7` is also dated 2026-10-09, while the preceding listed release, `wal2json_2_6`, is dated 2024-04-25. These facts indicate current development activity, but they do not remove PostgreSQL-specific upgrade work.
The project uses the `BSD-3-Clause` license. The repository includes a `LICENSE` file. Organizations redistributing a binary or incorporating source should review that file and preserve the license and copyright notices it requires. This is a licensing identification, not legal advice.
Upgrades have two separate compatibility surfaces. First, wal2json is built against PostgreSQL through PGXS, so `pg_config` must identify the intended PostgreSQL installation. Second, recent PostgreSQL security fixes restrict output plugin loading through `output_plugin_libraries`. The README names exact fixed minor versions, which means an upgrade checklist must record the server's full version, not merely its major branch. The new restriction also changes configuration behavior: a wal2json build can be present yet fail to load when the library is absent from `output_plugin_libraries`.
Editorial conclusion
Engineers should consider wal2json when a PostgreSQL integration needs row-level changes as JSON and its transaction boundary and metadata options fit the consumer. Operators should not choose it for an unsupported PostgreSQL platform or a workload that requires unchanged or old rows without checking replica identity first. Before adoption, verify the `output_plugin_libraries` requirement on the exact PostgreSQL minor release, confirm that `pg_config` points to the intended installation, and decide whether the consumer needs format version 1 or format version 2.
Frequently asked questions
What does wal2json do in PostgreSQL?
It is a logical decoding output plugin that exposes PostgreSQL row changes as JSON through logical replication slots or a special SQL API. Old row availability depends on replica identity.
How do I install wal2json on Debian or Ubuntu?
The README gives `sudo apt-get install postgresql-18-wal2json` for PostgreSQL 18. Source builds also require PostgreSQL development headers and a `pg_config` on the search path.
Should I use wal2json format version 1 or format version 2?
Format version 1 emits one JSON object per transaction, while format version 2 emits one object per tuple and can add transaction boundary records. Choose according to whether the consumer processes transactions or individual changes.
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/eulerto-wal2json)Was this useful?