# Valkey Valkey is a powerful, open-source alternative to Redis, offering full compatibility with Redis clients while providing an independent development path focused on community-driven innovation. Deploy and manage Valkey in Zerops' fully managed infrastructure to get instant access to high-performance in-memory data storage. :::tip Valkey is our recommended Redis alternative as KeyDB's development has slowed significantly in recent times. ::: ## Supported Versions Currently supported Valkey versions: Import configuration version: ## Service Configuration Zerops offers Valkey in two deployment configurations to meet different availability requirements. ### Single Setup - Single node deployment on port `6379` (non-TLS) and `6380` (TLS) - Suitable for development or non-critical workloads See [Persistence](#persistence) for how data is stored and recovered. ### HA (High Availability) Setup The HA deployment is a 3-node cluster with automatic failover, fronted by an HAProxy load balancer on every node. - 3-node configuration: 1 primary + 2 replicas - Client-facing ports (available on every node): - `6379` — read/write (non-TLS), routed to the current primary - `6380` — read/write over TLS, routed to the current primary - `7000` — read-only (non-TLS), load-balanced across replicas - `7001` — read-only over TLS, load-balanced across replicas - Failover is handled by a built-in [Sentinel](https://valkey.io/topics/sentinel/) cluster. When the primary becomes unreachable, a replica is promoted automatically and HAProxy starts routing writes to it. - TLS is terminated at HAProxy. - Connect your application to the standard ports — the address never changes when the primary moves. :::note Replica reads (ports `7000`/`7001`) can lag slightly behind the primary due to asynchronous replication. ::: **Failover client impact:** expect roughly 10–15 seconds of write unavailability while a new primary is elected and HAProxy reconverges. Read traffic on surviving replicas is unaffected. :::tip Trusting the TLS certificate The certificates served on the TLS ports (`6380` and `7001`) are signed by the Zerops Certificate Authority. To verify them from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `redis-cli --tls --cacert ./zerops-ca.pem -h -p 6380 -a `. ::: ## Connecting Zerops generates the connection details as environment variables on the Valkey service. Reference them from another service in the same project as `` — for a service named `db`, the connection string is ``. The examples below assume the hostname `db`. | Variable | Example value | Notes | |---|---|---| | `hostname` | `db` | Service hostname; reachable as `db.zerops` inside the project | | `port` | `6379` | Plain (non-TLS) port | | `portTls` | `6380` | TLS port | | `password` | *(generated)* | Password for the `default` user (sensitive) | | `connectionString` | `redis://default:@db.zerops:6379` | Ready-to-use non-TLS URL | | `connectionTlsString` | `rediss://default:@db.zerops:6380` | Ready-to-use TLS URL | In **HA mode** four additional variables expose the read-only replica endpoints (load-balanced across replicas): | Variable | Example value | Notes | |---|---|---| | `portReplicas` | `7000` | Read-only plain port | | `portTlsReplicas` | `7001` | Read-only TLS port | | `connectionStringReplicas` | `redis://default:@db.zerops:7000` | Read-only non-TLS URL | | `connectionTlsStringReplicas` | `rediss://default:@db.zerops:7001` | Read-only TLS URL | The connection string format is `redis://default:@.zerops:` (or `rediss://` for TLS). The username is always `default`. :::note Authentication Valkey requires a password. It is generated automatically, exposed as the sensitive `` variable, and already embedded in the `connectionString` variables above. Connect with it directly — e.g. `redis-cli -h db.zerops -p 6379 -a "$db_password"`. Services created **without** a `password` variable (older deployments) keep working without authentication and are unaffected. **All deployments created since this release require the password.** ::: ### Idle connection timeout Valkey closes connections that stay **idle for 5 minutes** (`timeout 300`). This is intentional on the managed instances — we avoid keeping infinite idle connections open. Older Valkey services ran with no timeout (`timeout 0`); if you connected before this change, your connections used to stay open indefinitely. "Idle" means **no commands sent on the connection** — the server resets the timer on every command, so a busy connection is never closed. The connections most likely to be affected are long-lived ones that sit waiting rather than sending commands, typically **pub/sub subscribers** and **blocking reads** (`BLPOP`, `XREAD`, …). Most clients reconnect automatically, so you may only see log lines such as `Redis subscriber socket closed; reconnecting if possible.` — but the reconnect churn can drop pub/sub messages published in the gap. To keep idle connections open, send an application-level **`PING` on an interval shorter than 300s**. A TCP keep-alive alone is **not** enough — keepalive packets live below the application layer and don't count as Valkey commands, so they don't reset the idle timer. Many clients have a built-in option for this. For example, [node-redis](https://github.com/redis/node-redis): ```js const redisClient = createClient({ url: redisURL, pingInterval: 10000, // send PING every 10s; keeps the connection under the 300s idle limit }); ``` If your client has no equivalent option, run your own heartbeat on every long-lived connection: ```js const heartbeat = setInterval(() => { publisher.ping().catch(() => {}); subscriber.ping().catch(() => {}); }, 60000); // any interval under 300s ``` For ordinary request/response traffic, a [connection pool](https://valkey.io/topics/clients/) that recycles connections handles this transparently. ## Persistence Valkey persists data to disk with **AOF (append-only file)**, so the dataset survives restarts and is rebuilt automatically on startup. - **AOF is enabled** (`appendonly yes`) and synced to disk **every second** (`appendfsync everysec`). After an unclean crash you lose at most ~1 second of the most recent writes. - **RDB snapshots are disabled** (`save ""`) — durability relies on AOF, not periodic snapshots. **Durability by mode:** - **Single:** the AOF lives on the node's local disk. Data survives service restarts but is lost if the underlying hardware node fails and no backup exists. - **HA:** writes are additionally replicated to two replicas, so the dataset survives the loss of any single node via automatic failover. :::note Backups Platform-managed encrypted backups are available for both Single and HA setups. They are **disabled by default** — enable them on the service if you need point-in-time recovery beyond AOF and replication. ::: ## Memory and Autoscaling You don't set `maxmemory` directly. Zerops sizes it at **80% of the container's available RAM** — precisely 80% of the *smaller* of your configured maximum RAM and the cgroup-allocated RAM. It is re-evaluated and adjusted automatically about every 30 seconds, so `maxmemory` tracks the container as it scales vertically. The remaining 20% covers Valkey's internal overhead (fork on AOF rewrite / replica sync, fragmentation) and the OS. :::warning Keep minimum free RAM above 20% when customizing autoscaling If you edit the autoscaling configuration, keep the **minimum free RAM above 20%**. Zerops caps `maxmemory` at 80% of available RAM, so the dataset alone can never push free RAM below 20%. If your minimum free RAM threshold is at or below 20%, the scale-up trigger may **never fire at all** — free RAM never crosses it, so the service stays stuck at its current size and starts evicting keys (or rejecting writes under `noeviction`) instead of scaling up. Setting the threshold above 20% lets the dataset's growth toward the 80% cap cross the trigger, so the service scales up in time and keeps headroom for the fork during an AOF rewrite or replica sync. The built-in profiles all keep this threshold above 20%. ::: :::note Check the logs for OOM events Watch the service's runtime logs for out-of-memory events — typically the kernel OOM-killer terminating and restarting Valkey when a fork during an AOF rewrite or replica sync briefly inflates memory. Recurring OOMs mean the reserved headroom isn't enough for your workload's peaks. Raise the **minimum free RAM** (more headroom) or the **minimum RAM** (a higher floor) until they stop. ::: ## Tunable Parameters The `maxmemory-policy` Valkey setting is exposed as an **autoscaling profile override**. In the GUI, open the service's **Automatic scaling configuration**, click **Adjust scaling** and set them under **Overrides**. Zerops applies the change live — **no service restart**, no client reconnect. In HA mode the change is rolled out to every node. To set the parameters at creation time, use `profileOverrides` in your import YAML (a `profile` must be selected to use overrides — available profiles are `hobby`, `staging` and `production`): ```yaml services: - hostname: redis type: valkey:ha@7.2 profile: staging profileOverrides: maxmemory-policy: noeviction ``` :::note Migrating from environment variables Services created before profile overrides existed configure this setting via the `VALKEY_MAXMEMORY_POLICY` environment variable. It keeps working, but once a profile override is set it takes precedence over the environment variable. ::: ### `maxmemory-policy` Default: `allkeys-lru`. Controls what Valkey does when the dataset reaches `maxmemory`. | Value | Behavior | When to use | |---|---|---| | `noeviction` | Reject writes with an OOM error | Datasets where every key must be preserved (session storage without TTL, job queues). Requires careful capacity planning. | | `allkeys-lru` | Evict least-recently-used keys | General-purpose caching — the safe default | | `allkeys-lfu` | Evict least-frequently-used keys | Hot/cold workloads where access frequency matters more than recency | | `allkeys-random` | Evict random keys | Uniform access patterns (rare) | | `volatile-lru` | Evict LRU keys *with a TTL set* | Mixed workloads: persistent keys without TTL are protected, cache keys with TTL are evictable | | `volatile-lfu` | Evict LFU keys with a TTL | Same as `volatile-lru`, frequency-based | | `volatile-random` | Evict random keys with a TTL | Rarely appropriate | | `volatile-ttl` | Evict keys with the shortest remaining TTL | When TTL reflects priority | :::warning `noeviction` and memory pressure With `noeviction`, Valkey cannot free memory on its own — once the dataset reaches `maxmemory`, writes fail with OOM errors until the service scales up or keys are deleted. Make sure your autoscaling limits (maximum RAM) leave enough room for the dataset's growth. ::: ## Metrics Prometheus-compatible metrics are exported by default for scraping, on the port given by the `ZEROPS_PROMETHEUS_PORT` variable (`db:9121`). ## Learn More - [Official Valkey Documentation](https://valkey.io/docs) - Comprehensive guide to Valkey features ## Support For advanced configurations or custom requirements: - Join our [Discord community](https://discord.gg/zeropsio) - Contact support via [email](mailto:support@zerops.io)