Configuration
SetupConfiguration.json, environment overrides, GUCs, and naming rules.
Two layers, one vocabulary:
| Layer | Case | Example |
|---|---|---|
SetupConfiguration.json |
PascalCase | GatewayListenPort |
| Environment overrides | SCREAMING_SNAKE_CASE | POSTRESP_PORT_NUMBER |
Environment variables override the JSON file when set. Prefer POSTRESP_* in
examples and docs; Redis/Valkey names are also accepted so you can merge an
existing redis/valkey compose service onto the Postgres image. Typical Docker
installs listen on 0.0.0.0:6379 and connect to Postgres as postresp /
postresp / postgres.
Prefix rules
- PostRESP —
POSTRESP_(preferred; wins when set). - Redis / Valkey —
REDIS_*/VALKEY_*(+ALLOW_EMPTY_PASSWORD). - Official Postgres image —
POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DBfor SQL init only (not RESP secret fallbacks). - In-container Postgres dial —
POSTGRESQL_HOST/POSTGRESQL_PORT; gateway database isPOSTRESP_DATABASE(sharesPOSTGRES_DBby default).
Priority for overlapping redis-facing settings: PostRESP → Valkey → Redis. Empty values are ignored.
Environment ↔ JSON map
| Preferred | Also accepted | JSON field | Default |
|---|---|---|---|
POSTRESP_PORT_NUMBER |
VALKEY_PORT_NUMBER, REDIS_PORT_NUMBER |
GatewayListenPort |
6379 |
POSTRESP_ALLOW_REMOTE_CONNECTIONS |
VALKEY_ALLOW_REMOTE_CONNECTIONS, REDIS_ALLOW_REMOTE_CONNECTIONS |
inverts UseLocalHost |
unset (code: local; Docker JSON: remote on) |
POSTRESP_PASSWORD |
VALKEY_PASSWORD, REDIS_PASSWORD, *_PASSWORD_FILE |
Password (RESP wire secret; not POSTGRES_PASSWORD) |
Docker: generate if unset; JSON: postresp |
POSTRESP_USERNAME |
Username |
postresp |
|
POSTRESP_DATABASE |
POSTRESP_POSTGRESQL_DATABASE, POSTGRESQL_DATABASE, POSTGRES_DB |
PostgresDatabase |
share POSTGRES_DB / postgres |
POSTRESP_STORAGE_MODE |
StorageMode (unlogged | logged) |
unlogged |
|
POSTRESP_REQUIRE_POSTGRES |
RequirePostgres |
unset / false |
|
POSTRESP_ASYNC_RUNTIME_WORKER_THREADS |
AsyncRuntimeWorkerThreads |
2 |
|
ALLOW_EMPTY_PASSWORD |
inverse of RequireClientAuth |
unset (RequireClientAuth=false) |
|
POSTGRESQL_HOST |
POSTRESP_POSTGRESQL_HOST |
PostgresHostName |
127.0.0.1 (Docker: unix socket) |
POSTGRESQL_PORT |
POSTRESP_POSTGRESQL_PORT |
PostgresPort |
5432 |
Booleans accept 1 / true / yes and 0 / false / no
(POSTRESP_ALLOW_REMOTE_CONNECTIONS=true|false works).
Bind address: Rust defaults are loopback-only (UseLocalHost: true). The
Docker image’s JSON sets UseLocalHost: false so -p 6379:6379 works.
POSTRESP_ALLOW_REMOTE_CONNECTIONS=false forces loopback.
Wire auth: off by default (RequireClientAuth: false). Enable with
RequireClientAuth: true in JSON or ALLOW_EMPTY_PASSWORD=no (env alone).
ALLOW_EMPTY_PASSWORD=yes forces auth off even when JSON has
RequireClientAuth: true. On Docker, unset password → random secret on first
start (see Authentication). Standalone JSON still defaults
to Password: postresp — do not enable wire auth with that value.
Database: same as the official Postgres image — postgres when
POSTGRES_DB is unset (schema pgresp). Override with POSTRESP_DATABASE
only when you need a separate database.
POSTRESP_PORT_NUMBER=6380
POSTRESP_PASSWORD=secret
POSTRESP_ALLOW_REMOTE_CONNECTIONS=true
POSTGRESQL_PORT=5433
Example config file
{
"GatewayListenPort": 6379,
"UseLocalHost": false,
"PostgresHostName": "/var/run/postgresql",
"PostgresPort": 5432,
"PostgresDatabase": "postgres",
"Username": "postresp",
"Password": "postresp",
"RequirePostgres": true,
"RequireClientAuth": false,
"StorageMode": "unlogged",
"AsyncRuntimeWorkerThreads": 2
}
Point Postgres at the file with:
shared_preload_libraries = 'pg_cron,pg_resp_gw_host,pg_prewarm'
pg_prewarm.autoprewarm = on
redis_gateway.database = 'postgres'
redis_gateway.setup_configuration_file = '/etc/postresp/SetupConfiguration.json'
GUCs
In-process host GUCs (require shared_preload_libraries including
pg_resp_gw_host):
redis_gateway.databaseredis_gateway.setup_configuration_filepg_resp.ttl_delete_batch_size(default1000) — SQL TTL sweeper keys/roundpg_resp.ttl_delete_max_rounds(default10) — rounds perdelete_expired_keyscall
Tune the TTL pair with ALTER SYSTEM / postgresql.conf + pg_reload_conf(), or
SET before a manual CALL pgresp.delete_expired_keys().
pg_cron
pg_cron is a Postgres extension that
runs scheduled SQL. PostRESP uses it for active TTL expiry: job
pg_resp_ttl_task calls pgresp.delete_expired_keys() once a minute.
Docker / compose preload pg_cron and set cron.database_name to the product
database. Init creates the extension; CREATE EXTENSION pg_resp schedules the
job when pg_cron is present.
| Setting | Role |
|---|---|
shared_preload_libraries includes pg_cron |
Required for the scheduler |
cron.database_name |
Database where the job runs (must match where you create extensions) |
Lazy expiry on read/write still works without pg_cron; without it, expired
keys are only removed when touched. Batch size for the sweeper is controlled by
the pg_resp.ttl_delete_* settings above — see
Commands › TTL.
pg_prewarm
pg_prewarm ships with a standard PostgreSQL install. Docker / compose
preload it and leave autoprewarm on by default (see
Buffer cache prewarm):
| Setting | Default | Meaning |
|---|---|---|
pg_prewarm.autoprewarm |
on |
Remember and reload recently cached table pages across restarts |
pg_prewarm.autoprewarm_interval |
300s |
How often to save that page list |
Compose convenience (maps to the setting above; not a gateway JSON field):
| Environment | Effect | Default |
|---|---|---|
PG_PREWARM_AUTOPREWARM |
on | off for pg_prewarm.autoprewarm |
on |
Postgres server settings are a separate surface from gateway env/JSON — prefer
the names in postgresql.conf. The compose variable above exists only so
compose can toggle autoprewarm without editing the command array.
Memory and buffer cache
Keys live in Postgres heaps and indexes (pgresp.*), not in a dedicated
in-process Redis dict. The full keyspace does not need to fit in RAM —
only the hot working set should, via shared_buffers and the OS page cache.
Cold keys stay on disk until read.
| Knob | Where | Guidance |
|---|---|---|
shared_buffers |
postgresql.conf |
Size for the hot set you want resident, not the whole dataset. Default Docker images leave Postgres defaults; raise this when steady-state GET latency matters and the working set is larger than the default. |
| OS page cache | host / VM RAM | Postgres relies on the OS to cache table pages beyond shared_buffers. Leave headroom so the kernel can hold warm pgresp.* pages. |
pg_prewarm.autoprewarm |
see above | Reloads the previous hot set after restart so you are not starting from an empty cache. |
StorageMode |
gateway env/JSON | unlogged vs logged changes WAL and crash behavior (Storage modes); it does not change the dual-table encoding size. |
AsyncRuntimeWorkerThreads |
gateway env/JSON | Caps gateway async workers (default 2). Raise only if CPU is idle under concurrent RESP load; storage still dominates SET cost — see Benchmarks. |
Disk vs Redis RAM. Tiny string keys are stored twice in spirit (registry row in
keys + payload in strings) plus btree indexes, so on-disk bytes per key are
typically higher than Redis/used_memory for the same logical shape. That is
expected: you trade denser always-RAM encoding for SQL visibility and datasets
larger than memory. Do not compare Redis INFO memory to Postgres process
RSS — Postgres always carries shared buffers, catalogs, and backends.
Measure schema size when capacity-planning disk:
SELECT pg_size_pretty(SUM(pg_total_relation_size(c.oid))) AS pgresp_total
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'pgresp' AND c.relkind = 'r';
Container / image exceptions
POSTGRES_USER— SQL superuser only (defaultpostgres); never the RESP rolePOSTGRES_PASSWORD/POSTGRES_DB— official Postgres image init onlyPGPORT— libpq default port inside the container (set fromPOSTGRESQL_PORT)PG_PREWARM_AUTOPREWARM— compose →pg_prewarm.autoprewarmonly (see above)
VALKEY_* / REDIS_* / ALLOW_EMPTY_PASSWORD are accepted Redis/Valkey
aliases. Persist data on the Postgres volume (/var/lib/postgresql); there is
no separate Redis data directory.