> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slipway.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Redis

> Run Redis-compatible in-memory storage for caches, sessions and job queues.

Redis on slipway runs [Valkey](https://valkey.io) 8, the Linux Foundation's
Redis-compatible fork. Every Redis client works unchanged: the wire protocol, the commands,
the ACLs and the `redis://` and `rediss://` URL schemes are Redis's.

Siblings reach the instance at its service name (`redis:6379`). It has no public endpoint
unless you enable external access.

## Creating an instance

**Console**

Select **New → Database**, then **Redis**. The form asks for a name, the compute
allocation, a maxmemory policy and a persistence posture.

**slipway.yaml**

```yaml slipway.yaml theme={"system"}
version: 1

databases:
  - name: cache
    engine: redis
    memory: 1GB

services:
  - name: api
    runtime: docker
    env:
      CACHE_URL: ${service.cache.url}
```

`diskSizeGB` is optional on Redis and required on every other engine. Redis is a cache
by default, and its disk is what persistence buys.

The memory you configure is the working-set promise. slipway sets `maxmemory` to about 80%
of it, leaving headroom for snapshots and connections.

### Maxmemory policy

What happens when memory fills, chosen at creation.

| Policy | Behaviour | Use for |
| - | - | - |
| `allkeys-lru` | Evicts the least recently used keys. The default. | Caches |
| `noeviction` | Writes return an error when memory is full. | Job queues, where dropping an entry loses work |
| `allkeys-lfu`, `volatile-lru`, `volatile-lfu`, `volatile-ttl`, `allkeys-random`, `volatile-random` | The remaining Redis policies. | Workloads that know exactly what they want |

### Persistence

| Posture | What it does |
| - | - |
| Off | In-memory only. A restart starts clean and nothing is billed for storage. |
| Snapshot | Periodic point-in-time saves to a disk. A crash loses writes since the last save. |
| Journal and snapshot | An append-only journal fsynced every second, plus snapshots. The most durable option. |

The default is Off. With persistence on, the disk mounts at `/data` and is backed up on a
schedule. See [Disks](/data/disks).

## Authentication

Each instance is provisioned with a generated password stored as the project secret
`<SERVICE>_PASSWORD` and enforced with `--requirepass`. The account is the built-in ACL
user `default`, so URLs read `redis://default:<password>@…`. Authenticating with the
password alone reaches the same account.

Additional users are managed on the service's **Credentials** tab. Each is created live as
a full-access ACL user with a generated password stored as a revealable project secret.
ACL users can be **rotated** from the same tab — a fresh password is applied live and the
backing secret rewritten; redeploy connected services to pick it up. (Rotating the
built-in `default` account's requirepass is not supported yet.)

> [!WARNING]
>
> With persistence **Off**, ACL users live only as long as the process, like everything else
> in the instance. With persistence on they are saved to `/data/users.acl` and survive
> restarts.

## Connecting

```yaml slipway.yaml theme={"system"}
services:
  - name: api
    env:
      CACHE_URL: ${service.cache.url}
```

`${service.cache.url}` resolves to `redis://default:<password>@cache:6379`.

Available fields: `url`, `user` (always `default`), `password`, `host`, `port`, and
`external_url` when external access is on. There is no `database` field, because the Redis
protocol has no database identity.

## External access

Off by default. An admin can expose the instance from the service's Connection card.

```
rediss://default:<password>@<service>-<id8>-kv.db.<zone>:6379
```

TLS is required. The gateway terminates it and routes on the hostname, and the password
still authenticates end to end.

### Your client must send SNI

Every external instance shares one address, so the gateway has nothing to route on but the
server name your client sends in the TLS handshake. Connect by hostname, never by IP.
Without SNI the connection is answered with:

```
ERR TLS SNI is required to route this connection, but your client did not send a server name.
```

Most clients send it by default, including `redis-cli`, `ioredis`, `node-redis`,
`redis-py` and `go-redis`. Two need configuring:

| Client | What to set |
| - | - |
| Redis Insight | Tick **Use SNI** in the connection's TLS settings, with the hostname as the servername |
| stunnel | `sni = <service>-<id8>-kv.db.<zone>` in the client section |

To check an endpoint from a shell:

```bash theme={"system"}
redis-cli --tls -u 'rediss://default:<password>@<service>-<id8>-kv.db.<zone>:6379' ping
```

> [!NOTE]
>
> Endpoints created before this naming landed end in `.kv.<zone>` rather than
> `-kv.db.<zone>`. They keep working and do not need changing.

## High availability

By default a Redis instance is one pod with one disk. If the machine it runs on fails, the
disk has to be reattached elsewhere before anything answers again, which takes a few
minutes.

High availability runs three copies instead: a primary and two replicas, each on its own
disk and, where the cluster allows it, on a different machine. The replicas continuously
stream the primary's changes, and a Sentinel alongside every member watches for the
primary going quiet. If it does, the members elect a replacement and slipway moves the
service onto it, usually within about fifteen seconds.

Nothing about how you connect changes. The service keeps its name, its port and its
password, so `${service.cache.url}`, your sibling services and external access all keep
working across a failover — your client reconnects to the same host and reaches the new
primary. **No Sentinel-aware client library is needed.**

**Console**

Open the database and go to its **High Availability** tab, then turn the switch on.
You can also turn it on in the **Availability** panel when you create it. Either way
it is the same setting, and you can change it whenever you like.

**slipway.yaml**

```yaml theme={"system"}
databases:
  - name: cache
    engine: redis
    diskSizeGB: 10
    highAvailability: true
    haMembers: 3   # optional; 3 to 20, defaults to 3
```

### Persistence is required

A replicated Redis needs a disk. A primary that restarts with an empty dataset replicates
that emptiness to every replica, so the cache posture (persistence **off**) is available
at one member only. Turning high availability on in the console switches persistence on
for you; the API refuses the combination outright.

### How many copies

Three by default. You can run up to 20 — each extra member is one more failure the cluster
absorbs, one more read replica, and one more copy of the compute and disk on your bill.
Three is the floor, because with two, losing either one leaves a cluster that cannot
survive a second failure.

Changing the count is live: members are added or removed in place, and slipway hands the
primary role over before removing anything, so a scale-down costs one reconnect rather
than a failover.

### What it costs

Every member is a full copy of the allocation and the disk, so three members bill three
times one member. High availability is available on the Pro plan and above.

### What you should know

Replication is asynchronous. A failover promotes the most current replica, but writes the
primary had not yet sent can be lost — the window is normally milliseconds. **This is not
a backup**: replication copies mistakes as faithfully as it copies good writes. Snapshots
remain how you go back in time, and they are taken from the lowest-numbered member.

Credentials created on the **Credentials** tab are applied to every member, because Redis
ACL state is stored per node rather than being replicated.

## Metrics

The service overview shows CPU, memory and active connections, sampled every 30 seconds
and streamed, so a new client appears on the next sample without reloading.

The [Metrics tab](/observability/metrics) charts those over a window you choose, plus disk
usage against the volume's size when persistence is on.

There is no request, latency or egress panel. A data service's traffic goes through the
TCP gateway rather than the HTTP edge, so the edge never counts it. Connections are the
throughput signal instead.

## Pricing

| What | Rate |
| - | - |
| CPU | \$8.76 per vCPU per month |
| Memory | \$4.38 per GiB per month |
| Disk | \$0.25 per GiB per month |
| Volume backups | \$0.05 per GiB per month |
| Object storage | \$0.05 per GiB per month |
| Egress beyond the plan allowance | \$0.01 per GB |

Compute is metered by the second against the allocation a service is configured with, so
a service that sleeps costs nothing while it is asleep. Disk, backups and object storage
are metered on what is provisioned or held, whether or not the service is running.

Redis is priced on the allocation you configure, with CPU reserved rather than burstable.
A persistence disk is billed on its provisioned size.

## FAQ

**Is this actually Redis?**

It is Valkey, the fork maintained by the Linux Foundation after Redis changed licence.
Clients, commands and URLs are identical. The image is `valkey/valkey` and the password
environment variable is `VALKEY_PASSWORD`.

**Can I use it without a disk?**

**Yes**, and that is the default. Leave persistence off for a cache. The one exception is
[high availability](#high-availability), which needs a disk to replicate from.

**Do I need a Sentinel-aware client?**

**No.** Sentinel runs alongside every member and decides which one is the primary, but you
never talk to it: slipway points the service name at whichever member currently holds the
role, so an ordinary client connecting to `cache:6379` always reaches the primary.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.