Skip to content

Repository files navigation

pgraft

Raft consensus for distributed PostgreSQL clusters

PostgreSQLGoLicense: MITDocumentation

Documentation · Quick Start · Releases · Discussions


Overview

pgraft is a PostgreSQL extension that brings the Raft consensus algorithm to distributed PostgreSQL clusters. It provides automatic leader election, crash-safe log replication, and provable split-brain prevention, built on the production-grade etcd-io/raft library and integrated through a native background worker — no external agents or dependencies.

FeatureDescription
ConsensusAutomatic leader electionQuorum-based, deterministic, fully automated
DurabilityCrash-safe replicationState changes replicated and persisted across nodes
SafetySplit-brain preventionGuaranteed by the Raft quorum protocol
AvailabilityAutomatic failoverSub-second detection and recovery
IntegrationNative PostgreSQLBackground-worker architecture, managed via SQL
Storageetcd-compatible KV storeRaft-replicated key/value storage included
ObservabilityStatus & metricsCluster status, replication stats, structured logging

Supported platforms

PlatformPostgreSQLStatus
Linux — RHEL / Rocky / AlmaLinux14 – 18Supported
Linux — Ubuntu / Debian14 – 18Supported
macOS14 – 18Supported

Note

CI builds and smoke-tests every push against PostgreSQL 14 through 18. Official release packages are published for 16, 17 and 18; 14 and 15 are build-from-source.


Installation

From source
# Prerequisites: PostgreSQL 14+, Go 1.23+, json-c, pkg-config
git clone https://github.com/pgelephant/pgraft.git
cd pgraft
make
sudo make install

Build against a specific PostgreSQL installation:

make PG_CONFIG=/usr/pgsql-17/bin/pg_config
sudo make install PG_CONFIG=/usr/pgsql-17/bin/pg_config
Pre-built packages

Download the appropriate package from the Releases page.

# RHEL / Rocky / AlmaLinux
sudo dnf install pgraft_17-2.0.0-1.el9.x86_64.rpm
# Ubuntu / Debian
sudo apt install ./postgresql-17-pgraft_2.0.0-1_amd64.deb
Build prerequisites by platform
# Ubuntu / Debian
sudo apt update
sudo apt install build-essential postgresql-server-dev-17 golang-go \
libjson-c-dev pkg-config git
# RHEL / Rocky / AlmaLinux
sudo dnf install gcc make postgresql17-devel golang json-c-devel \
pkg-config git
# macOS
brew install postgresql@17 go json-c pkg-config

Tip

See the complete installation guide for detailed, platform-specific instructions.


Configuration

Add the following to postgresql.conf on every node, adjusting pgraft.name and the addresses per node:

shared_preload_libraries = 'pgraft'# Node identity (must be unique and appear in initial_cluster)pgraft.name = 'node1'# Cluster membership — identical on all nodespgraft.initial_cluster = 'node1=http://10.0.1.11:7001,node2=http://10.0.1.12:7001,node3=http://10.0.1.13:7001'pgraft.initial_cluster_state = 'new'pgraft.initial_cluster_token = 'pgraft-cluster-1'# Local Raft transport endpointpgraft.listen_peer_urls = 'http://0.0.0.0:7001'# Persistent storage for logs, snapshots, and HardStatepgraft.data_dir = '/var/lib/postgresql/pgraft'# Consensus timing (optional)pgraft.election_timeout = 1000 # millisecondspgraft.heartbeat_interval = 100 # milliseconds

Important

  • pgraft.name must be unique and match a member name in pgraft.initial_cluster.
  • pgraft.initial_cluster and pgraft.initial_cluster_token must be identical on all nodes.
  • Node IDs are assigned automatically from each member's position in initial_cluster.
  • Changes to shared_preload_libraries require a PostgreSQL restart.

See the configuration reference for the full list of parameters.


Quick start

Create the extension on each node — the cluster forms automatically from the initial_cluster configuration:

CREATE EXTENSION pgraft;
-- Cluster state, leadership, and membershipSELECT*FROMpgraft.get_cluster_status();
SELECT*FROMpgraft.get_nodes();

Note

Leader election completes within a few seconds of the cluster starting. Query pgraft.get_leader() to confirm a leader has been elected before issuing leader-only operations.

Follow the quick start guide for a complete walkthrough.

Upgrading from 1.0

Install the new files, then update the extension in each database and restart the server so the C and Go libraries are reloaded together:

ALTER EXTENSION pgraft UPDATE TO '2.0.0';

Two things change, and both need attention before you upgrade.

Every object moved into the pgraft schema and lost its pgraft_ prefix.pgraft_get_cluster_status() is now pgraft.get_cluster_status(), and so on for all 34 functions and 19 views. The upgrade drops the old unqualified objects, so update your application first, or at least at the same time. It does not use CASCADE: if something of yours depends on an old function, the upgrade stops rather than dropping your object along with it.

Argument lists and result columns are unchanged, so the rename is the only edit a caller needs.

Privileges are stricter. Functions that mutate cluster or key/value state are no longer executable by PUBLIC. Grant them explicitly to the roles that need them.


Usage

Cluster status and health

SELECTpgraft.is_leader(); -- is this node the leader?SELECTpgraft.get_leader(); -- current leader idSELECT*FROMpgraft.get_cluster_status(); -- full statusSELECT*FROMpgraft.get_nodes(); -- all membersSELECT*FROMpgraft.log_get_replication_status(); -- replication progressSELECT*FROMpgraft.log_get_stats(); -- log statistics

Key/value store (etcd-compatible)

SELECTpgraft.kv_put('app/config', '{"timeout":30,"retries":3}'); -- leader onlySELECTpgraft.kv_get('app/config'); -- any nodeSELECTpgraft.kv_list_keys();
SELECTpgraft.kv_delete('app/config'); -- leader only

Dynamic membership

SELECTpgraft.add_node(4, '10.0.1.14', 7004); -- leader onlySELECTpgraft.remove_node(4); -- leader only

Warning

Write operations — pgraft.kv_put, pgraft.kv_delete, pgraft.add_node and pgraft.remove_node — must be issued on the leader. Guard automated jobs with pgraft.is_leader() to avoid errors on followers.

See the SQL function reference for the complete API.


Architecture

flowchart TD
subgraph PG["PostgreSQL process"]
direction TB
BW["Background worker (C)<br/>ticks every 100&nbsp;ms"]
API["SQL API (C)<br/>cluster · status · KV · log"]
end
BW -->|pgraft_go_tick| GO["Go Raft engine<br/>(etcd-io/raft)"]
API -.->|manage / query| GO
GO --> ELECT["Leader election"]
GO --> REPL["Log replication"]
GO --> STORE["Persistent storage<br/>logs · snapshots · HardState"]
GO --> NET["TCP transport"]
NET <-->|Raft RPC| PEERS["Peer nodes"]
Loading
LayerResponsibility
C layerPostgreSQL integration, SQL functions, background worker
Go layerRaft consensus engine (etcd-io/raft)
StorageDurable logs, snapshots, and HardState on disk
NetworkTCP transport for inter-node Raft communication

The background worker ticks the Raft state machine every 100 ms. The Go engine handles elections, log replication, and consensus; committed entries are applied locally on every node, and all state is persisted for crash safety. Management and monitoring are exposed entirely through SQL.

Further reading: architecture · automatic replication · split-brain protection.


Testing with Docker

The pgraft_cluster.py helper provisions a multi-node cluster for local testing:

cd examples
./pgraft_cluster.py --docker --init --nodes 3 # start a 3-node cluster
./pgraft_cluster.py --docker --status # inspect status
./pgraft_cluster.py --docker --destroy # tear down

See the cluster script guide.


Performance characteristics

MetricTypical valueNotes
Tick interval100 msBackground-worker frequency
Election timeout1000 msConfigurable (500 – 3000 ms recommended)
Heartbeat interval100 msConfigurable (50 – 500 ms recommended)
Memory per node~50 MBGo runtime and Raft state
CPU (idle)< 1 %Background-worker overhead
Failover time1 – 3 sElection timeout plus detection

Production deployment

System requirements
ResourceMinimum (testing)Recommended (production)
CPU2 cores4+ cores
Memory2 GB / node8 GB+ / node
Disk10 GB50 GB+ SSD
Network100 Mbps1 Gbps+, < 10 ms latency

Recommended practices:

  • Run an odd number of nodes (3, 5, or 7) for a stable quorum.
  • Keep inter-node latency below 10 ms.
  • Use a dedicated network for Raft traffic where possible.
  • Monitor leader changes and replication lag, and alert on them.
  • Maintain regular PostgreSQL backups alongside Raft logs.
  • Test failover thoroughly before going to production.

See the best-practices guide.


Troubleshooting

Background worker not starting
SHOW shared_preload_libraries; -- must include 'pgraft'

shared_preload_libraries changes require a PostgreSQL restart.

No leader elected
SELECTpgraft.get_leader(), pgraft.is_leader();

Allow a few seconds after cluster start. Confirm that pgraft.initial_cluster and pgraft.initial_cluster_token are identical on every node and that the peer ports are reachable.

A node cannot join
SELECT name, setting FROM pg_settings WHERE name LIKE'pgraft.%';

Verify that this node's pgraft.name appears in pgraft.initial_cluster and that its listen_peer_urls endpoint is reachable from the other nodes.

High CPU usage
SELECT elections_triggered FROMpgraft.get_cluster_status();

Repeated elections usually indicate network instability or an election_timeout that is too low for the link latency; increase it.

See the full troubleshooting guide.


Documentation

SectionTopics
Getting startedInstallation, quick start
User guideConfiguration, SQL functions, cluster operations, tutorial
ConceptsArchitecture, automatic replication, split-brain protection
OperationsMonitoring, troubleshooting, best practices
DevelopmentBuilding, testing, contributing

Contributing

Contributions are welcome — bug reports, feature requests, documentation, and code. A typical workflow:

  1. Search existing issues and discussions.
  2. Open an issue describing the problem or proposal.
  3. Fork the repository and develop on a feature branch.
  4. Submit a pull request with tests and documentation.

Please read the contributing guidelines before opening a pull request.

make installcheck # regression tests

Technology stack

ComponentTechnology
Core languageC (PostgreSQL extension)
Consensus engineGo — etcd-io/raft
Build systemPostgreSQL PGXS, GNU Make
JSON parsingjson-c
DocumentationMkDocs (Material theme)
CI/CDGitHub Actions
PackagingRPM (RHEL/Rocky), DEB (Ubuntu/Debian)

License

Released under the MIT License. Copyright © 2024–2025 pgElephant.


Built for the PostgreSQL community.

Documentation · Issues · Discussions

About

PostgreSQL extension for Raft-based leader election, log replication and cluster coordination. Background worker, shared memory state, clean C core with a Go bridge to etcd-io/raft. Includes an etcd-compatible key/value store. PG14-18.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

23 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages