Back to Blog
Tutorial8 min read2026-07-18

How to Deploy Valkey (the Redis Fork) on PandaStack

Valkey is the Linux Foundation's open-source fork of Redis 7.2, created after Redis changed its license in 2024. Here's how to run a self-hosted Valkey cache on PandaStack, when to use it over managed Redis, and how to connect from your app.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

In early 2024 Redis changed its license away from open source, and the community — backed by the Linux Foundation, AWS, Google, and Oracle — forked the last BSD version into Valkey (https://valkey.io). It's a drop-in fork of Redis 7.2: same RESP protocol, same commands, same client libraries. If your code talks to Redis, it talks to Valkey unchanged. This post shows you how to run Valkey on PandaStack and, importantly, when you should just use PandaStack's managed Redis instead.

Managed Redis vs. self-hosted Valkey — decide first

PandaStack offers managed Redis as a first-class database (backups, monitoring, connection pooling, one-click creation). For 90% of caching and session needs, that's the right choice — you don't manage anything. Run Valkey as a self-hosted container when:

  • You specifically want the OSI-approved open-source license for compliance reasons.
  • You need a Valkey-only feature or module the managed Redis doesn't expose.
  • You want full control over the exact config and version.

If none of those apply, create a managed Redis and skip to "connecting from your app." No shame in the easy path.

Step 1: Dockerfile

Valkey ships an official image, valkey/valkey. The main decision is persistence: a pure cache needs none, but if you use Valkey as a job queue or store anything you'd miss, enable AOF (append-only file) on a volume.

FROM valkey/valkey:8-alpine

# Config supplied at runtime; data (if persisted) on a volume at /data
EXPOSE 6379

CMD ["valkey-server", \
     "--appendonly", "yes", \
     "--dir", "/data", \
     "--requirepass", "$VALKEY_PASSWORD", \
     "--maxmemory", "256mb", \
     "--maxmemory-policy", "allkeys-lru"]

As with SurrealDB, the exec-form CMD won't expand $VALKEY_PASSWORD. Use a shell entrypoint:

FROM valkey/valkey:8-alpine
EXPOSE 6379
COPY start.sh /start.sh
ENTRYPOINT ["/bin/sh", "/start.sh"]
# start.sh
#!/bin/sh
exec valkey-server \
  --appendonly yes \
  --dir /data \
  --requirepass "$VALKEY_PASSWORD" \
  --maxmemory 256mb \
  --maxmemory-policy allkeys-lru

allkeys-lru evicts least-recently-used keys when memory fills — the sane default for a cache. If you're using it as a durable queue, use noeviction instead so it never silently drops data.

Step 2: Always set a password

--requirepass is not optional on a public instance. An unauthenticated Redis/Valkey on the internet gets found by automated scanners within minutes and turned into someone's botnet C2 or crypto miner. Generate one:

openssl rand -hex 24

Step 3: Deploy

  1. 1Push the repo to GitHub.
  2. 2Dashboard → New App → Container App, connect the repo, container port 6379.
  3. 3If you enabled appendonly, attach a persistent volume at /data.
  4. 4Add env var VALKEY_PASSWORD.
  5. 5Deploy.

CLI equivalent:

npm install -g @pandastack/cli
panda login
panda deploy

Step 4: Connect from your app

Because Valkey speaks the Redis protocol, every Redis client works. Node with ioredis:

import Redis from 'ioredis'

const cache = new Redis(process.env.VALKEY_URL)
// redis://:password@your-valkey.pandastack.io:6379

await cache.set('greeting', 'hi', 'EX', 60)   // 60s TTL
const v = await cache.get('greeting')

Python with redis-py:

import os, redis
r = redis.from_url(os.environ["VALKEY_URL"])
r.setex("greeting", 60, "hi")
print(r.get("greeting"))

Set VALKEY_URL in your app's environment variables:

redis://:YOUR_PASSWORD@your-valkey.pandastack.io:6379

Step 5: Common uses

  • Caching — wrap expensive DB queries: check Valkey first, fall back to Postgres, write the result back with a TTL.
  • Sessions — store session data with an expiry so logged-out sessions clean themselves up.
  • Rate limitingINCR a per-user key with EXPIRE; reject when it exceeds your limit.
  • Job queuesLPUSH/BRPOP a list, or use a library like BullMQ (which works against Valkey unchanged).

A cache-aside helper:

async function getUser(id) {
  const key = `user:${id}`
  const cached = await cache.get(key)
  if (cached) return JSON.parse(cached)

  const user = await db.query('SELECT * FROM users WHERE id = $1', [id])
  await cache.set(key, JSON.stringify(user), 'EX', 300)  // 5 min
  return user
}

Step 6: Monitor memory

Valkey lives and dies by memory. Check it:

valkey-cli -a "$VALKEY_PASSWORD" INFO memory | grep used_memory_human

Set a PandaStack alert (email/Slack/webhook) on the container's memory usage so you know before eviction starts silently dropping your cache. If you're evicting constantly, raise --maxmemory or move hot data patterns around.

Valkey vs. Redis: does the fork matter?

For your code, no — they're wire-compatible today. The divergence is at the license and governance level. Valkey has continued adding features (like improved multi-threading) under an open-source license. If you have no license constraint, managed Redis on PandaStack is simpler; if you want open-source guarantees, self-hosted Valkey gives you them.

Wrap-up

Valkey is Redis without the license drama, and on PandaStack it's a container app with a password, optionally a /data volume, and any Redis client. But be honest about whether you need it — managed Redis is one click and zero maintenance. Docs: https://docs.pandastack.io. Start free at https://dashboard.pandastack.io.

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also