Skip to content

Redis

Run Redis as a pgcli addon — a standalone key-value store for cache, session, ranking and counter data, with selectable major versions 7 and 8

Redis is the in-memory key-value store most applications reach for when they need a cache, a session backend, leaderboards (sorted sets) or atomic counters. pgcli runs it as a standalone, top-level addon with the same CLI surface as the object stores (install / start / stop / logs / autostart / remove), managed entirely through pg.yaml.

It is deliberately the simplest addon in the fleet:

  • One container, one port, one password. requirepass is generated on the first install and stored in pg.yaml — an unauthenticated Redis is not a reachable state.
  • Version selection. It is the first version-selectable addon: --version 7|8 resolves through a built-in table to a pinned docker.io/library/redis tag (7 → 7.4.11, 8 → 8.10.2, the default). --image still bypasses the table with any tag you like.
  • Persistence you can dial in. By default the dataset is an RDB snapshot in a bind-mounted host directory — it survives restarts, and survives pg addon remove (without --clean-data) so reinstalling the same name revives the data. --aof adds the write-ahead log on top for crash-safe, no-eviction stores, and --save no turns snapshots off entirely (see Parameters).

Pick Redis for cache/session/ranking/counter workloads next to your PostgreSQL instances; it is independent of the PG stack, coexists with any other addon, and several instances (even across majors) can run on one host.

Out of scope: Sentinel (automatic failover) is not managed by pgcli. Redis’s native cluster is supported — --cluster turns instances into cluster-enabled members that you assemble once yourself with pg redis-cli -- --cluster create (masters-only by default; add per-master followers with --cluster-replicas N; see Native cluster). Read replicas are too — --replica-of turns an instance into a read-only follower of another (see Read replicas and Known limitations).

Parameters

pgcli keeps Redis’s parameter surface deliberately small: one flag per knob, each mapping to a native redis-server option — argv overrides through the image’s own entrypoint, no redis.conf file is generated, and one container per instance runs the plain upstream image (no pgcli wrapper, unlike rustfs). The table lists every knob and its default:

Flag / pg.yaml key Default Redis option Meaning
--version / version 8 — (picks the image tag) major to install (see Version selection)
--image / image_tag resolved from the version table — override the tag verbatim
--port / port auto from redis_start_port (base 6379) --port host port
--listen / listen 0.0.0.0 --bind bind address (127.0.0.1 to tighten)
--password / password generated, 20 chars --requirepass auth; always required (a replica’s must equal the master’s)
--maxmemory / maxmemory unset (no cap) --maxmemory dataset cap that turns eviction on
--maxmemory-policy / maxmemory_policy allkeys-lru --maxmemory-policy eviction policy, only under a cap
--aof / aof off --appendonly yes write-ahead log on top of the snapshot
--appendfsync / appendfsync everysec (Redis’s own) --appendfsync AOF flush strength, only with --aof
--save / save Redis’s default schedule --save RDB snapshot plan; no disables snapshots
--replica-of / replica_host+replica_port unset (master) --replicaof + --masterauth read-only replica of a local master addon (its host/port/password are resolved from the config)
--replica-of-host / replica_host — --replicaof master address for a cross-host replica (pair with --replica-of-port + --password)
--replica-of-port / replica_port — --replicaof master port, paired with --replica-of-host
--cluster / cluster unset (standalone) --cluster-enabled yes + --masterauth native-cluster member: non-empty is the group name — same value means same cluster, and every member of a group shares the first member’s password (--cluster create authenticates all operands with one password, exactly like a replica’s password must equal its master’s). Every member also carries --masterauth so any node Redis later promotes to a follower can authenticate to its master. Mutually exclusive with --replica-of/--replica-of-host — an instance is either a cluster member or a read replica, never both. pgcli installs the node; you assemble the cluster yourself — see Native cluster
--cluster-replicas / cluster_replicas 0 (masters-only) — (echoed into the suggested --cluster create only) per-master followers for the assemble step: the summary counts 3*(1+N) nodes and the printed command ends with --cluster-replicas N. Which members become followers is Redis’s decision at --cluster create, not at install. A group property like the password — the first member sets it, later members inherit it, an explicit mismatch is rejected
--advertise-host / advertise_host unset (127.0.0.1, single-host) --cluster-announce-ip/-port/-bus-port the address this member announces to peers — a LAN IP, required for a cross-host cluster (Redis’s cluster bus has no NAT/port remapping)
--data-dir / data_dir <base-dir>/addon/redis/<name>/data --dir /data (host dir bind-mounted at /data) where the data lives
— autostart: false — start on boot (pg autostart enable --redis)

How the knobs combine:

  • requirepass is always on — an unauthenticated Redis is not a reachable state, even if --password is left empty by hand in pg.yaml.
  • Persistence defaults to RDB snapshots — Redis’s own save schedule, plus a final snapshot on shutdown (--stop-timeout 30 gives Redis the time to write it) and a replay from dump.rdb at start.
  • --aof adds the write-ahead log (--appendonly yes) alongside the snapshot — the durable, no-eviction shape. --appendfsync tunes its flush: always (durability) / everysec (the default) / no (throughput). The AOF lives in an appendonlydir/ under the data dir and is replayed before the snapshot, so it is the source of truth when both are on.
  • --save no disables snapshots — pair it with --aof for an AOF-only store (the summary then reads aof only); on its own it means a purely in-memory instance that loses its dataset on restart (the install warns).
  • --maxmemory implies eviction, defaulting to allkeys-lru — the cap means “cache, evict to stay under”. Pass --maxmemory-policy noeviction for a hard ceiling (writes fail past the cap instead of evicting), or omit --maxmemory entirely for no cap. The policy flag requires --maxmemory; --appendfsync requires --aof — the CLI rejects those combinations before it pulls or creates anything.
  • --replica-of makes a read replica — see Read replicas. The persistence/eviction knobs stay orthogonal: a replica may cap memory or enable AOF exactly like a master.
  • --cluster makes a cluster member, and is mutually exclusive with --replica-of/--replica-of-host — an instance is one role or the other, never both. Members of the same --cluster group share the first member’s password automatically (a later --cluster member with a different --password is rejected before anything is pulled or created), and the per-master follower count set by --cluster-replicas N is inherited the same way. See Native cluster.

Not every Redis option is a flag, by design: the multi-node control plane (Sentinel, automatic failover) is out of scope, and so is cluster orchestration — pgcli installs cluster-enabled members but never runs --cluster create, --cluster add-node, resharding, or scale-in for you; see Native cluster and Known limitations. Read replicas are supported (Read replicas); it is the orchestration (promoting a replica automatically when the master dies) that pgcli leaves to you. And --image is the escape hatch for the engine itself: pg addon install redis --image docker.io/valkey/valkey:8 runs Valkey (the Redis fork), its major reverse-parsing as 8.

Version selection

--version picks a major; the table maps each major to a pinned patch tag:

Major Default image tag Select with
7 docker.io/library/redis:7.4.11 pg addon install redis --name cache --version 7
8 docker.io/library/redis:8.10.2 pg addon install redis --name cache (8 is the default)

Resolution rules:

  • --version 7 (or 8) → the table’s tag is stored in image_tag, the major in version;
  • --image <tag> → your tag wins outright; the major is reverse-parsed from it for display (redis:7.2.4 → 7), or left empty if unparseable (the tag is then shown verbatim);
  • neither → major 8;
  • an unknown --version → error listing the available majors.

Both majors can run side by side on one host — different tags, different ports from the same pool. The tags track the latest patch of each major and are bumped together with the docs/images.md rows.

Install

# default: major 8, instance name "redis", port auto-assigned from 6379
pg addon install redis

# a named cache instance on major 7, with a memory cap (evicts at the cap)
pg addon install redis --name legacy --version 7 --maxmemory 256mb

# loopback-only instead of the all-interfaces default
pg addon install redis --name cache --listen 127.0.0.1

# pin the password (stable across reinstalls) and a fixed port
pg addon install redis --name sessions --password 'S3ssions!' --port 6379

# a read-only replica of the local "sessions" instance (borrows its password,
# major and endpoint)
pg addon install redis --name sessions-ro --replica-of sessions

The install summary prints everything a client needs:

✓ redis installed: "cache"
  Container:  pgcli-redis-default-cache
  Version:    8
  Image:      docker.io/library/redis:8.10.2
  Data:       ~/pg/addon/redis/cache/data
  Address:    0.0.0.0:6379
  Role:       master
  Persistence: rdb snapshots (default save schedule)

  Password:    <generated>

  Client:      pg redis-cli ping
  Raw DSN:     redis://:<password>@0.0.0.0:6379/0
  NOTE: listening on every interface; the password above is the only gate.
        loopback-only: pg addon install redis --name cache --listen 127.0.0.1 --force

Security model. listen defaults to 0.0.0.0 — on Linux (host networking) the port is published on every interface, and requirepass is the only gate. That is convenient for app-on-another-host setups but means the password is load-bearing: pass --listen 127.0.0.1 to keep an instance loopback-only. pg addon list and the logs never print the password; reveal it on demand with pg addon password redis --name cache or pg addon list --show-password (or read pg.yaml).

Re-running install is idempotent: a running container is left alone, a stopped one is started. To apply changed ports/listen/password/image, add --force (the container is recreated from the config; the data dir is untouched). The persistence knobs (--aof/--appendfsync/--save/ --maxmemory-policy) take effect the same way.

Using Redis

pg redis-cli

pg redis-cli runs Redis’s own client from a throwaway container of the addon’s image — no host install, no password typing:

pg redis-cli ping                              # PONG
pg redis-cli set session:42 '{"user":"alice"}' # ok — auth is injected
pg redis-cli get session:42
pg redis-cli lrange queue 0 -1                 # negative indexes pass through
pg redis-cli --name legacy zrevrange leaderboard 0 9

The local target is --name <addon> or, when omitted, the first redis addon by name (with several installed, the chosen target is announced on stderr). pgcli’s own flags are parsed only before the command word; everything after is forwarded to redis-cli verbatim — negative indexes and option flags (via --) work that way.

Reaching a remote endpoint — --host/--port override where the client connects, without registering the remote as an addon:

# reuse a local addon's image + password, but talk to a remote host (e.g. a replica)
pg redis-cli --host 10.0.0.7 ping
pg redis-cli --host 10.0.0.7 --port 6380 --name cache info

# no local addon at all: default-major image, password via REDISCLI_AUTH
REDISCLI_AUTH=s3cret pg redis-cli --host 10.0.0.7 dbsize

Use these instead of redis-cli’s own -h/-p: those sit after the command word and would be read as command arguments (ping -h 10.0.0.7 errors), while pgcli injects the connection -h/-p itself. REDISCLI_AUTH (redis-cli’s native env var), if set, overrides the stored password in every mode:

REDISCLI_AUTH=otherpass pg redis-cli dbsize

Application connections

Any Redis client works; the DSN printed at install has the shape redis://:<password>@<host>:<port>/0. For TLS you would need a stunnel or redis’ own TLS build in front — see Known limitations.

Read replicas

--replica-of turns a new instance into a read-only replica of an existing master addon: it streams the master’s writes continuously and serves reads, while writes to it are rejected with READONLY. This is read scaling and data redundancy, not high availability — pgcli does not run Sentinel, so a dead master is not promoted automatically (see Known limitations).

# master (writable)
pg addon install redis --name cache

# same-host replica: it borrows the master's major, password and endpoint
pg addon install redis --name cache-ro --replica-of cache

A local --replica-of resolves everything from the config: the replica adopts the master’s version (cross-major replication is unsupported — a mismatch is a fast error), its password, and the endpoint 127.0.0.1:<master-port>. That one password then serves both requirepass (the replica’s own clients auth with it) and --masterauth (the replica authenticating to the master), so --password/--maxmemory/--aof etc. stay exactly as on a master. The stored replica_host/replica_port mean pg addon start rebuilds the same --replicaof argv even if the master is gone from the config.

Cross-host masters use the explicit form — pgcli cannot look up a remote master’s password, so you supply it (it must equal the master’s):

pg addon install redis --name cache-r2 \
    --replica-of-host 10.0.0.7 --replica-of-port 6379 --password <master-password>

pg addon list and the install summary show a Role: line — master, or replica of <host>:<port> (read-only) — and pg redis-cli --name cache-ro info replication reports role:replica with master_link_status:up once the (initial, RDB-carrying) sync completes. Send reads to the replica and writes to the master, e.g. with the DSNs:

# read traffic -> the replica
redis://:<password>@127.0.0.1:<replica-port>/0

To promote a replica to an independent master at runtime (the manual failover pgcli deliberately leaves to you), clear its replication and then, if you want it to persist across restarts, drop its role from the config:

pg redis-cli --name cache-ro replicaof no one   # stop following the master
pg addon remove redis --name cache-ro          # keep the data, forget the role
pg addon install redis --name cache-ro         # reinstall as a plain master

Native cluster

--cluster turns instances into members of a Redis native cluster — sharding by slot (16384 of them), not a read replica of one master. This is the only multi-node topology pgcli supports; Sentinel is not.

pgcli’s role is deliberately narrow: it installs cluster-enabled nodes, it does not assemble them. That is Redis’s own two-step flow, not a pgcli invention — a cluster is cluster-enabled yes servers plus one redis-cli --cluster create command run against all of them at once. Splitting those two steps means pgcli never has to guess “is this the last member I’m waiting for, should I form the group now” (an etcd-style auto-bootstrap state machine); assembling is always your decision, made once, the same way you’d do it against bare redis-server.

# 1. install the members — one --cluster <token> turns each into a cluster-enabled
#    node; the same token means "same cluster". Minimum 3 masters (Redis's own
#    quorum rule). masters-only is the default (3 installs, --cluster-replicas 0);
#    to give each master a follower, install 3*(1+N) members and pass
#    --cluster-replicas N to the first one (the rest inherit it) — see step 2.
pg addon install redis --name n1 --cluster app --maxmemory 10mb
pg addon install redis --name n2 --cluster app --maxmemory 10mb
pg addon install redis --name n3 --cluster app --maxmemory 10mb

Members of one group share the first member’s password automatically: --cluster create authenticates every operand node with a single -a (here, via the one REDISCLI_AUTH pg redis-cli injects), so one password has to reach the whole group — the same rule that makes a read replica’s password equal its master’s. A later --cluster member installed with a different --password is rejected up front, before anything is pulled or created; omit --password and the group’s own value is inherited. Every member also emits --masterauth (the same shared password) in its argv: at --cluster create time Redis may promote any node to a follower, and a follower needs --masterauth to authenticate to its master — without it it spins forever in a reconnect storm (master_link_status:down, CPU pinned). --cluster and --replica-of/--replica-of-host are mutually exclusive on one install — an instance is either a cluster member or a read replica, never both.

# 2. assemble once, through pg redis-cli's passthrough (pgcli never runs this)
pg redis-cli --name n1 -- --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 --cluster-replicas 0

The three addr:port operands are every member’s PeerAddr:port — that’s 127.0.0.1:<port> for a single-host cluster, or each member’s --advertise-host:<port> for a cross-host one (see below). The install summary already prints this exact command, built from whatever --cluster app members are configured at that moment (pg redis-cli --name n3 -- --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 --cluster-replicas 0), so it is copy-pasteable rather than something to reconstruct by hand:

-> NOTE: native-cluster member of "app" — it comes up cluster-enabled but INCOMPLETE
   until you assemble the group once (see the "Cluster:" line below). pgcli does not
   run --cluster create for you.
...
  Cluster:     "app" — 3 masters configured. Assemble once (pgcli does not run this):
               pg redis-cli --name n3 -- --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 --cluster-replicas 0
               (bus port = client+10000; for cross-host peers open it on the firewall, and give each member --advertise-host)

--cluster-replicas 0 is masters-only — every member holds its own slice of the slots and none of them has a follower. To give each master a follower (so one master’s slot range survives that node dying), pass --cluster-replicas N on the first install and add enough members: each master needs itself plus its N followers, so the total is 3*(1+N) — for N=1 that’s 6 members:

pg addon install redis --name n1 --cluster app --cluster-replicas 1 --maxmemory 10mb
pg addon install redis --name n2 --cluster app --maxmemory 10mb   # inherits replicas=1
# …install to 6 members total, then:
pg redis-cli --name n1 -- --cluster create \
    127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 \
    127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1

Which members Redis elects as masters vs followers is its decision at --cluster create (it balances followers across hosts where it can), so the pgcli instance names are deliberately role-neutral, and a follower re-links from its own nodes.conf after a restart — role and masterauth pairing survive, no re-create. The install summary switches from “3 masters configured” to counting nodes (“6 nodes configured”) once followers are in play, and echoes the group’s --cluster-replicas N into the suggested command; it never calls a follower-set node a master.

After assembling

A pg redis-cli pointed at a cluster member is automatically a cluster-aware client: pgcli injects redis-cli’s own -c flag so a get/set that lands on the “wrong” node follows its MOVED redirect to the node that actually owns the slot — no -c to remember, and it doesn’t matter which --name you happen to point at:

pg redis-cli --name n1 set foo bar      # might be served by n3 via MOVED
pg redis-cli --name n2 get foo          # same key, followed the redirect again
pg redis-cli --name n1 -- --cluster check 127.0.0.1:6379   # admin subcommands, not -c's job

The last line is the exception, not a rule to remember: when the command is redis-cli’s own --cluster <subcommand> (which dials the nodes named in its operands itself), pgcli suppresses the -c injection — it’s the assembly/admin surface from step 2, not a data command.

The auto--c above depends on pgcli reading a local cluster member from pg.yaml (the --name path). When you reach the cluster remotely with --host/--port from a machine that has no such addon configured, pgcli has no way to know the endpoint is a cluster node, so it injects nothing — and an unredirected get/set that lands on the wrong node just returns MOVED .... Forward redis-cli’s -c yourself (it is redis-cli’s own flag, so it goes after the -- passthrough, before the command word):

export REDISCLI_AUTH=<the group password>
pg redis-cli --host 10.10.0.158 --port 6379 -- -c get foo   # follows MOVED for you
pg redis-cli --host 10.10.0.158 --port 6379 -- -c set foo bar

-c matters for writes as much as reads: without it a set aimed at a non-owner returns MOVED and is not applied, so the key never exists. Put -c on the write, and any single node serves the whole keyspace.

You can also skip the env var and pass the password with redis-cli’s own -a — it is a connection option too, so it goes in the same passthrough slot, before the command word:

pg redis-cli --host 10.10.0.158 --port 6379 -- -a <the group password> -c get foo

Two caveats distinguish it from REDISCLI_AUTH: redis-cli prints a security warning on every invocation (-a/-u on a command line is visible to other users via ps), and placing the flag after the command word (get foo -a …) fails with “wrong number of arguments” — it would be passed as a command argument. For anything beyond a one-off command, prefer the env var; they are otherwise equivalent for authentication.

If your clients cannot be made cluster-aware at all, put a Predixy proxy in front of the cluster: it follows the redirects itself and exposes one plain redis:// endpoint.

The cluster bus is a second port per member: always client port + 10000 (Redis’s own fixed rule, e.g. 6379→16379) — it is not drawn from redis_start_port, not stored in pg.yaml, and pg addon list shows it alongside the token:

    Role:        cluster member of "app" (127.0.0.1:6381)
    Cluster:     app (bus 16381)

Topology is self-healing: each node’s --cluster-config-file nodes.conf lives in its own --dir /data bind mount, so pg addon stop/start (or a host reboot) brings the whole cluster back with no re-create step — same start-only model as autostart for everything else here.

Two commands check the cluster’s health directly, both through the passthrough (yes, the -c one is a data-path client flag, so it goes after the --):

# one member's view of the whole cluster — look for cluster_state:ok / cluster_size:N
pg redis-cli --host <ip> --port <port> -- -c cluster info
# full group health check (slot coverage, replicas, links) — redis-cli's admin surface
pg redis-cli -- --cluster check <ip>:<port>

Cross-host members: --advertise-host

A single-host cluster dials peers at 127.0.0.1 and works with no extra flags. Redis’s cluster bus does not support NAT or port remapping, so members on different hosts must announce the address peers can actually reach:

# on 10.10.0.158 — the first member decides the group's one password; read it back:
pg addon install redis --name n1 --cluster app --advertise-host 10.10.0.158
PW=$(pg addon password redis --name n1)
# on 10.10.0.159 and 10.10.0.160 — carry that same password across:
pg addon install redis --name n2 --cluster app --advertise-host 10.10.0.159 --password "$PW"
pg addon install redis --name n3 --cluster app --advertise-host 10.10.0.160 --password "$PW"
# assemble once (from any host that reaches all three) — the operands are each
# member's advertised address + its port (one member per host here, each host's
# own pool starts at 6379, so all three are :6379):
pg redis-cli --name n1 -- --cluster create \
    10.10.0.158:6379 10.10.0.159:6379 10.10.0.160:6379 --cluster-replicas 0

--advertise-host adds --cluster-announce-ip/-port/-bus-port to the node’s argv, and PeerAddr (used to build the --cluster create operands above) switches from 127.0.0.1 to that address. Two things to get right on your side: open each member’s bus port (client+10000 — 16379 at the default 6379) on the firewall between hosts — not just the client port — and every member of the group must carry the flag, not only the ones being joined later.

The --password "$PW" on every host after the first is not decoration: the shared-password inheritance only works within one pg.yaml — on a single host, later members automatically adopt the group’s password; across hosts, each host has its own config file and generates its own secret. A cross-host cluster must therefore pin one password explicitly on every host, read from the first member with pg addon password.

(--cluster create authenticates every operand with that one password, so a mismatch surfaces as a per-node auth error.)

Status: cross-host clusters are verified end-to-end across three hosts (--advertise-host → --cluster-announce-*, cross-host --cluster create, MOVED redirects between hosts, and self-heal after a stop/start on each host). The single-host flow is additionally covered by the automated e2e (test/addon/test_redis_cluster.sh), which tests both shapes there: a three-master group and a 3-master × 1-follower group (which is how the missing---masterauth reconnect storm was caught). The multi-host case is so far a manual procedure, not yet in the suite.

Ports

Each instance takes one port from Redis’s own pool, redis_start_port (default 6379) — a separate cursor from the object stores’ shared minio_start_port pool, so a redis, a minio and a rustfs instance never collide:

pg addon install redis  --name cache    # 6379
pg addon install redis  --name sessions # 6380

--port fixes an instance to a specific port; auto-assignment skips anything already explicit or live on the host. A native-cluster member is no different here — the cluster bus port is always Redis’s own client+10000, derived, never drawn from the pool.

Configuration

Instances live under the top-level addons.redis map in pg.yaml:

namespace: default
redis_start_port: 6379     # Redis's own pool, separate from minio_start_port
addons:
  redis:
    cache:
      container_name: pgcli-redis-default-cache
      name: cache
      version: "8"                       # major as selected/stored
      image_tag: docker.io/library/redis:8.10.2
      # data_dir: /srv/redis-cache       # omit for <base-dir>/addon/redis/cache/data
      listen: 0.0.0.0                    # default (all interfaces); 127.0.0.1 to tighten
      port: 6379
      password: <generated>              # written on first install
      # maxmemory: 256mb                 # optional cap
      # maxmemory_policy: noeviction     # only with a cap; default allkeys-lru
      # aof: true                        # write-ahead log on top of snapshots
      # appendfsync: always              # only with aof; default everysec
      # save: "900 1 300 10"             # RDB schedule; "no" disables snapshots
      # replica_host: 127.0.0.1          # set by --replica-of: this is a read replica
      # replica_port: 6379               # the master's port, paired with replica_host
      # cluster: app                     # set by --cluster: this is a native-cluster member
      # cluster_replicas: 1              # set by --cluster-replicas: followers per master for --cluster create (0 = masters-only; group-shared)
      # advertise_host: 10.10.0.158      # set by --advertise-host: peer-visible address (cross-host only)
      autostart: false                   # pg autostart enable --redis --name cache

Edits to listen, port, password, maxmemory/maxmemory_policy, aof/appendfsync/save, replica_host/replica_port, cluster/cluster_replicas/advertise_host, image_tag/version, or data_dir take effect after the next pg addon install redis --name cache --force (or via the matching flags). The replica and cluster roles are normally set by the --replica-of* / --cluster (incl. --cluster-replicas) / --advertise-host flags rather than hand-edited — see Read replicas and Native cluster.

List

pg addon list
Infra add-ons (redis):
  redis (name: cache)
    Status:      running
    Version:     8
    Address:     0.0.0.0:6379
    Role:        master
    Auth:        on (requirepass)
    Maxmemory:   256mb (allkeys-lru)
    Persistence: rdb + aof (default save schedule, appendonly yes)
    Data:        ~/pg/addon/redis/cache/data
    Image:       docker.io/library/redis:8.10.2
    Container:   pgcli-redis-default-cache
    Client:      pg redis-cli --name cache ping

pg addon list never prints the password. To reveal it deliberately, add --show-password (it appends a Password: and a ready-to-paste Raw DSN: line to each Redis instance — and a Root password: line to each object store), or print just one instance’s value bare on stdout for scripting:

pg addon password redis --name cache
export REDISCLI_AUTH="$(pg addon password redis --name cache)"

pg addon password takes the same --name as the other subcommands (defaulting to the addon’s own name) and a --file that writes the value mode 0600 instead of to the terminal — prefer --file so the secret stays out of shell history and scrollback.

Start and stop

pg addon start redis --name cache
pg addon stop  redis --name cache

stop sends a graceful SIGTERM — with --stop-timeout 30 Redis writes its final RDB before exiting. start only starts an existing container (and self-heals an improper state by recreating it from the config).

Auto-start on Boot

Containers carry a --restart unless-stopped policy (crashes, not reboots). To bring instances up after a host reboot:

pg autostart enable --redis --name cache

Redis autostart is start-only (install the instance first) and replays the RDB snapshot from its data dir, so the dataset survives the reboot. Redis is independent of the PostgreSQL stack, so boot-time pg start --autostart starts it last.

Remove

pg addon remove redis --name cache            # container + config entry; data kept
pg addon remove redis --name cache --clean-data  # also delete the data dir

Without --clean-data the host data dir (and its dump.rdb) stays in place — reinstalling the same name revives the dataset. --clean-data deletes it, falling back through podman unshare when rootless podman’s subordinate uid makes Redis’s files undeletable by the host user. An empty per-instance parent directory is pruned; a custom data_dir parent is never touched.

Logs

pg logs addon redis --name cache        # last 50 lines
pg logs addon redis --name cache -f     # follow

Troubleshooting

  • NOAUTH Authentication required from a raw client — expected: every instance has a requirepass. Get it with pg addon password redis --name cache, or use pg redis-cli, which injects it.
  • maxmemory evicting more than you wanted — under a --maxmemory cap the default policy is allkeys-lru (evict any key to stay under: a cache, not a hard store). Pass --maxmemory-policy noeviction to make the cap a hard ceiling instead (writes fail past it rather than evicting), or omit --maxmemory for no cap at all.
  • AOF not replaying the newest writes — --appendfsync everysec (the default) can lose the last second of writes on a hard crash; use --appendfsync always when you cannot afford that. A graceful pg stop always flushes, so this only bites on an unclean kill.
  • Image not found at install — both majors are plain docker.io/library/redis images pulled on demand; on an air-gapped host, podman load the tar first (the catalog and export steps live in docs/images.md in the repo) and the pull is skipped.
  • A hand-edited version that is not in the table — install errors and suggests --image rather than silently rewriting your value.
  • Port already live — auto-assignment scans host listeners and skips them; pin --port when you need a stable number.
  • A replica rejects writes (READONLY) — that is the role, not a fault: send writes to the master. To make it an independent master, see Read replicas.
  • A freshly-created replica briefly shows master_link_status:down — normal during the first (RDB-carrying) full sync, and redis 8 reloads the link once more when the snapshot transfers over its rdbchannel. Watch info replication; it settles at up and role:replica.

Known limitations

  • No automatic failover — read replicas are supported (Read replicas) and native-cluster sharding is supported (Native cluster), but the HA control plane is not: Sentinel is out of scope, and so is cluster orchestration — pgcli installs cluster members but never assembles, rescales, or rebalances them. A replica gives read scaling and a redundant copy of the data, not a self-healing pair — when the master dies you promote a replica yourself (replicaof no one, above). A single instance with no replica is a single point: it can be made durable on disk with --aof, but it cannot fail over to another node.
  • Native cluster: assembly and reshaping stay manual — --cluster installs cluster-enabled nodes and --cluster-replicas N (echoed into the suggested command) lets each master have followers, so a follower auto-promotes when its master dies. What pgcli does NOT do is run --cluster create/add-node/ resharding/del-node for you, and removing a member (pg addon remove) is a plain delete with no slot reassignment — shrink or reshape the cluster at the Redis layer first (move its slots off, forget the node), then remove it. Also note a masters-only group (--cluster-replicas 0) has no follower to promote: there a dead master takes its slot range down with it until you intervene.
  • Cross-host cluster (--advertise-host) is manual, not in the e2e suite — the flag, the --cluster-announce-* argv it produces, and the firewall/bus-port rules are implemented, unit-tested, and verified by hand across three hosts (assembly, cross-host MOVED redirects, and self-heal all pass). The single-host flow (masters-only and 3-master × 1-follower) has an automated e2e; cross-host-with-followers has no automated e2e but relies on the same per-member --masterauth that makes followers link up on one host. See the status note in Native cluster.
  • No TLS — Redis 7’s native TLS exists in some builds but is not wired here; treat the network path as trusted and rely on requirepass, or keep the instance loopback-only (--listen 127.0.0.1). For a cross-host cluster that means the cluster bus traffic between members is unencrypted as well.
  • macOS is code-complete, untested — the bridge path (published ports, host.containers.internal for pg redis-cli) mirrors the object stores; it has not yet been exercised on a Mac.
  • Default persistence is RDB granularity — a crash loses writes since the last snapshot. Enable --aof when that gap matters (at everysec you still lose at most one second; always closes it); accept snapshots-only for cache/session data, or move durable data to PostgreSQL.