pg_local_cache 3.0.0

This Release
pg_local_cache 3.0.0
Date
Status
Stable
Other Releases
Abstract
Transaction-aware cache for PostgreSQL primary-key reads
Description
pg_local_cache keeps hot whole rows in bounded PostgreSQL shared memory for authenticated RESP reads. PostgreSQL remains authoritative, and writes publish transaction-aware invalidation fences before commit visibility.
Released By
bronnikov
License
MIT
Resources
Special Files
Tags

Extensions

pg_local_cache 3.0.0
Transaction-aware cache for RESP primary-key reads

Documentation

QUICKSTART
Try pg_local_cache locally {#try-pg_local_cache-locally}
CONTRIBUTING
Maintaining the docs and examples
node-postgres
Batch row lookups with node-postgres {#batch-row-lookups-with-node-postgres}
benchmarks-node
Node.js benchmarks {#nodejs-benchmarks}
benchmarks-go
Go benchmarks: SQL and RESP {#go-benchmarks-sql-and-resp}
resp
Connect over RESP {#connect-over-resp}
postgresql-redis-cache
PostgreSQL and Redis cache-aside {#postgresql-and-redis-cache-aside}
SECURITY
Security Policy
TECHNICAL
pg_local_cache technical reference {#pg_local_cache-technical-reference}
batch-primary-key-lookups
Batch PostgreSQL primary-key lookups {#batch-postgresql-primary-key-lookups}
CHANGELOG
Changelog
postgresql-caching
PostgreSQL caching decision guide {#postgresql-caching-decision-guide}
row-cache-vs-shared-buffers
PostgreSQL row cache vs shared_buffers {#postgresql-row-cache-vs-shared_buffers}
INSTALL_EXISTING
Install pg_local_cache on an existing PostgreSQL server {#install-pg_local_cache-on-an-existing-postgresql-server}
UPGRADING
Upgrade pg_local_cache from 2.x to 3.0.0 {#upgrade-pg_local_cache-from-2x-to-300}
go
Batch row lookups with Go and pgx {#batch-row-lookups-with-go-and-pgx}
BENCHMARKS
PostgreSQL cache benchmarks {#postgresql-cache-benchmarks}
cache-invalidation
Transaction-aware cache invalidation in PostgreSQL {#transaction-aware-cache-invalidation-in-postgresql}

README

pg_local_cache: PostgreSQL row cache

Version 3.0.0: authenticated RESP row reads, bounded shared memory, and transaction-aware invalidation for PostgreSQL 14-18.

Cache whole rows by their complete primary key. PostgreSQL remains the source of truth; ordinary writes invalidate affected entries. Ordinary SELECT queries are not rewritten. The limited RESP2 endpoint exposes MGET, SET, DEL, and scoped invalidation.

Documentation | Try locally | Benchmarks | Installation | Upgrade from 2.x | Technical reference

Measured: 839,678 single-key RESP requests/s

3.31× the prepared SQL throughput in one local comparison: 839,678 vs 253,790 requests/s. Apple M3 Max, PostgreSQL 16, Go, 256 connections, warm cache; median of three five-second samples on 15 September 2026. The recorded SQL mget comparison (186,296 requests/s) is from 2.x and was removed in 3.0.0; batch results differ. Conditions and raw data.

Run the same prepared-SQL/RESP matrix on Node.js and Go:

./examples/benchmark.sh all > comparison.json

Requires Docker, Node.js 20+ and Go 1.25+. Runs against a disposable demo database.

Try without changing an existing database

With Docker Compose, from this repository:

docker compose -f examples/compose.yaml -f examples/compose.resp.yaml up --build --wait

The demo builds the extension from your checkout. It binds PostgreSQL to loopback port 55432, stores disposable data in tmpfs, and mounts no host database. Follow the quickstart to run RESP reads and remove it.

With Node.js 20 or later, check the result contract and concurrent writes:

npm --prefix examples/node-postgres ci --ignore-scripts
npm --prefix examples/node-postgres run demo

Read whole rows by primary key over RESP

Attach a permanent table with a supported primary key:

SELECT local_cache.attach_table('public.items'::regclass);

Connect with RESP2 and issue MGET using the mapped table’s wire key:

MGET CRUD:app.public.items:{"id":42} CRUD:app.public.items:{"id":7}

RESP MGET preserves key order and duplicates. Missing rows return null. The listener’s workers use one configured PostgreSQL role; they do not inherit the network client’s SQL privileges, transaction, or snapshot. See the RESP guide for authentication and client examples.

Writes remain ordinary PostgreSQL:

UPDATE public.items SET value = 'new' WHERE id = 42;

Connection examples: Node.js, Go, RESP. See benchmark results for throughput and server resource use.

Consistency and workload fit

Each cache hit is checked against mapping, relation, transaction, row, and snapshot state. REPEATABLE READ, SERIALIZABLE, recovery, parallel execution, and transactions that wrote mapped data bypass the cache. Oversized or unsafe entries fall back to an indexed source-table read.

Worth measuring Keep using PostgreSQL directly for
Repeated complete primary-key reads Joins, ranges, aggregates, and full scans
A hot set of whole rows that fits the cache Arbitrary query-result caching
READ COMMITTED on one writable primary RLS, partitioned, or inherited tables
An application that can use authenticated RESP MGET Queries that need locking or have no measured benefit

The extension is not a Redis replacement. It provides no TTL, pub/sub, or distributed coordination. RESP reads run through the configured worker role, separately from application SQL sessions.

Related guides: PostgreSQL caching, PostgreSQL and Redis cache-aside, or batch primary-key lookups.

Install on an existing server

Release packages support PostgreSQL 14-18 on Linux for Debian/Ubuntu and RHEL-family distributions. First activation adds pg_local_cache to shared_preload_libraries and requires one controlled PostgreSQL restart. Use the installation guide for package verification, PGXN and source installation, configuration, restart, upgrade, and uninstall.

Configure the RESP listener:

shared_preload_libraries = 'pg_local_cache'
pg_local_cache.database = 'app'
pg_local_cache.role = 'local_cache_worker'
pg_local_cache.port = 6380
pg_local_cache.bind_address = '127.0.0.1'
pg_local_cache.auth_token_file = '/secure/path/token'
pg_local_cache.cache_entries = 16384
pg_local_cache.memory_budget_mb = 384

Preserve existing preload entries. Size cache entries, relation states, clients, workers, and the memory budget together before restart. Manual source installs also need the role and metadata grants before attaching a table; RESP reads use the configured worker role.

Useful administration functions:

SELECT local_cache.health();
SELECT local_cache.stats();
SELECT local_cache.reconcile_table('public.items'::regclass);
SELECT local_cache.detach_table('public.items'::regclass);

RESP2 endpoint

RESP2 supports authenticated, bounded MGET, SET, DEL, and scoped invalidation. Workers run under one configured PostgreSQL role; network clients do not inherit individual PostgreSQL ACLs. Keep the listener on loopback unless you deliberately enable plaintext network access on a trusted network. Native TLS is planned for PR 3b. Prefer pg_local_cache.auth_token_file over an inline token. See the technical reference.

Develop

Source builds use PostgreSQL’s PGXS toolchain and the target server’s headers. Follow the source-build procedure.

make verify-static source-test
make docker-smoke
node --test examples/node-postgres/queries.test.mjs

Report a workload | Releases | Contributing

License: MIT.