Migrating from Upstash to Layerbase
Short version: you copy the keyspace into managed Redis or Valkey and swap Upstash's REST client for an ordinary Redis driver. The wizard takes your Upstash account email and a management API key, lists your databases, and copies every key, type, and TTL with a non-blocking SCAN, so your live cache keeps serving while it runs; by hand it is a short ioredis script that SCANs the keyspace and DUMPs and RESTOREs each key with its TTL against the rediss:// endpoint. It is Redis on both ends, so your keys, values, data types, TTLs, pub/sub, and Lua scripts port directly and nothing is left behind. The two things that genuinely change are the bill, flat per instance instead of per command, and the client, which only matters if you call Redis straight from an edge runtime that cannot open a TCP socket.
Upstash made serverless Redis easy: pay per request, scale to zero, connect over HTTP from the edge. That model is perfect when you're at zero, and it gets unpredictable as you grow, because the meter runs on every command. A chatty cache or a rate limiter doing millions of ops a day turns into a bill you can't forecast, and you don't own the instance, you rent commands against it.
If you'd rather pay a flat per-instance price for Redis-compatible storage you can actually run, Valkey on Layerbase Cloud is the move. Valkey is the BSD-licensed Redis fork, wire-compatible with everything you already use. Your data copies over with one API key, and the only code change is swapping Upstash's REST client for a standard Redis driver (and even that only matters on the edge).
Just want it done? Start at layerbase.com/migrate/upstash. You sign in, the wizard opens with Upstash already selected, and it copies every key, type, and TTL into managed Redis (or Valkey) in one non-blocking scan: read-once, nothing written back to Upstash. The rest of this post is that same migration explained step by step, plus the manual path.
Contents
- What Actually Changes
- Set Up Valkey Locally with the Layerbase CLI
- Copy Your Data
- Swap the Client
- What to Test
- The Managed Path: Layerbase Cloud
- FAQ
What Actually Changes
Upstash speaks the Redis protocol, so your data structures, commands, and most of your code are unchanged. Two things differ:
- The pricing model. Upstash meters per request (with a fixed-plan option on top). Layerbase Valkey is flat per instance: the bill is the same whether you do a thousand ops a month or a billion. For anything past hobby traffic, this is the whole point of moving.
- The client. Upstash pushes
@upstash/redis, a REST/HTTP client built for edge runtimes that can't open raw TCP sockets. A standard Valkey server speaks the Redis wire protocol over TCP, so on a normal Node/Python/Go server you use a normal client (ioredis,redis,redis-py). If you specifically need HTTP access from an edge function, see the client section below.
What does not change: your keys, values, data types, TTLs, pub/sub, Lua scripts, and the commands you call. It's Redis on both ends.
Set Up Valkey Locally with the Layerbase CLI
Stand up Valkey locally first so you can copy your data into it and verify before touching production. The Layerbase CLI (formerly SpinDB) runs it with one command, no Docker. (What is the Layerbase CLI?)
Install the Layerbase CLI:
npm i -g layerbase # npm
pnpm add -g layerbase # pnpmCreate a Valkey instance:
lbase create upstash-migration -e valkey --startCheck the URL (it uses the redis:// scheme because Valkey speaks the same protocol):
lbase url upstash-migrationredis://127.0.0.1:6380Connect with redis-cli (or valkey-cli):
lbase connect upstash-migrationCopy Your Data
The managed wizard (one API key)
On Layerbase Cloud, the create flow does the copy. Choose Migrating from another platform, pick Upstash, and paste your Upstash account email and a management API key (Upstash console, then Account, then Management API). It lists your Redis databases; for the one you pick it reads the whole keyspace with a non-blocking SCAN and copies every key, type, and TTL into a fresh managed Valkey. No redis-cli gymnastics, no blocking KEYS *.
By hand with a scan + dump
If you'd rather do it yourself (or copy into the local Layerbase instance above), Upstash gives you a rediss:// endpoint, so any Redis client can read it. One warning first: DUMP returns a binary payload, and the obvious redis-cli loop that stuffs it into a shell variable mangles it, so RESTORE rejects every key with a checksum error. A dozen lines of ioredis keep the bytes intact:
npm i ioredis
SRC='rediss://default:<password>@<your-db>.upstash.io:6379' \
DST='redis://127.0.0.1:6380' \
node -e '
const Redis = require("ioredis")
const src = new Redis(process.env.SRC), dst = new Redis(process.env.DST)
;(async () => {
let cursor = "0", n = 0
do {
const [next, keys] = await src.scan(cursor, "COUNT", 500)
for (const key of keys) {
const [dump, ttl] = await Promise.all([src.dumpBuffer(key), src.pttl(key)])
if (dump) { await dst.restore(key, ttl > 0 ? ttl : 0, dump, "REPLACE"); n++ }
}
cursor = next
} while (cursor !== "0")
console.log(`copied ${n} keys`)
await src.quit(); await dst.quit()
})()'SCAN, never KEYS *, on a live database, and REPLACE makes the script safe to re-run. Tested against a Valkey 9 pair: strings containing NUL bytes, hashes with per-field TTLs, lists, sets, sorted sets, and a 90-second key expiry all came across byte for byte. For large keyspaces, prefer the managed wizard (it batches and resumes); the script is fine for small-to-medium caches. Upstash's serverless tier blocks BGSAVE/--rdb, which is why this is a per-key copy rather than an RDB file.
Swap the Client
If your app already uses a normal Redis client, you only change the connection string. The change that matters is for code using Upstash's REST client.
Before (Upstash REST client):
import { Redis } from '@upstash/redis'
const redis = Redis.fromEnv() // UPSTASH_REDIS_REST_URL + token
await redis.set('session:42', value, { ex: 3600 })
const v = await redis.get('session:42')After (standard Redis client over TCP):
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL!) // rediss://...cloud.layerbase.dev:port
await redis.set('session:42', value, 'EX', 3600)
const v = await redis.get('session:42')Same commands, slightly different option syntax. If you use the @vercel/kv or @auth/upstash-redis-adapter packages, they accept any Redis-compatible client, so point them at ioredis.
A note on edge runtimes: @upstash/redis exists because some edge platforms can't open TCP sockets. If you deploy to a Node runtime (most apps), ioredis is simpler. If you genuinely need HTTP from an edge function, keep that path behind a small Node API route that talks to Valkey over TCP.
What to Test
- Run your suite against the local Valkey. Commands behave identically; the protocol hasn't changed.
- Check TTL-sensitive logic. Confirm sessions, rate-limit windows, and cache expiries carried their TTLs across (the wizard and the
DUMP/RESTOREloop both preserve them; verify a few keys withPTTL). - Check connection handling. The REST client was stateless; with
ioredisuse a single client/pool per instance rather than constructing one per request, especially in serverless. - If you used Upstash for a queue, note that Layerbase's managed queue add-on, vqueue, runs on Valkey; a plain key/value copy brings your data, and the queue is a separate product.
The Managed Path: Layerbase Cloud
The hands-on version is worth doing once. When you want managed Valkey you don't run yourself, Layerbase Cloud provisions it in seconds with TLS, backups, and flat per-instance pricing, and the Migrating from another platform wizard does the copy from your Upstash API key. Off the per-command meter, onto an instance you own.
FAQ
Which credentials does the wizard want?
Upstash is a two-part key, so it asks for your account email alongside a management API key from the Upstash console (Account, then Management API). With both it lists your Redis databases and you pick one. If you would rather not mint a management key, the wizard also accepts a plain rediss:// TLS endpoint copied from the database's Connect tab, which points at exactly one database and skips the listing step. The REST URL and token are not an option either way, because copying a keyspace needs the wire protocol.
Does the copy interrupt my live cache?
No. The read uses a non-blocking SCAN rather than KEYS *, so Upstash keeps serving reads and writes throughout, and nothing is ever written back to the source. The gap to plan for is the one after the copy finishes: keys written to Upstash before you flip the client stay on Upstash, so cut over promptly or run the copy during a quiet window.
Do TTLs actually survive?
Yes, and it is the thing to verify first. The wizard copies the remaining TTL with each key, and the manual DUMP/RESTORE script preserves it too, which is why the PTTL value is carried through explicitly rather than reset. Check a few sessions, a rate-limit window, and a cache entry with PTTL on the new instance before you trust the whole keyspace.
Do I have to stop using @upstash/redis?
On a normal Node, Python, or Go server, yes, and it is an improvement: ioredis or redis talks the wire protocol over TCP with the same commands and slightly different option syntax. @upstash/redis only exists because some edge runtimes cannot open raw sockets, so if you genuinely call Redis from an edge function, keep that path behind a small Node API route that speaks TCP to Valkey. Packages like @vercel/kv and @auth/upstash-redis-adapter accept any Redis-compatible client, so they take ioredis as-is.
Redis or Valkey on the other side?
Wire-compatible either way, so your commands and data structures are identical and the copy is the same. Pick Valkey if you would rather not depend on the Redis license, or Redis if you want exact upstream. One thing does decide it for you: if Upstash was backing a message queue, land on Valkey, because the managed queue add-on vqueue runs on Valkey and a key/value copy alone does not bring a queue product with it.
Wrapping Up
Leaving Upstash is mostly a data copy plus a one-line client swap. It's Redis on both ends, so your commands and data structures port directly; the wins are predictable pricing and, on a Node runtime, a simpler standard client. Copy your keyspace with one API key through the wizard, or a --scan + DUMP/RESTORE loop by hand.
Manage your local Valkey instance with the Layerbase CLI:
lbase stop upstash-migration # Stop the server
lbase start upstash-migration # Start it again
lbase url upstash-migration # Print the connection URL
lbase list # See all your instancesThe Layerbase CLI handles 20+ database engines, so Valkey can sit next to your Postgres, Meilisearch, or Qdrant while you verify the move. Layerbase Desktop wraps it in a GUI on macOS. For the Redis-to-Valkey background, see Redis vs Valkey and Migrating from Redis to Valkey.
Keep reading
- Upstash vs Redis Cloud in 2026Upstash prices Redis per command and reaches it over HTTP. Redis Cloud prices it by memory and sells the query engine, JSON, and Active-Active on top. A 2026 comparison of the billing models, the free tiers, the connection limits, and what a small always-on app and a bursty serverless app actually cost on each.
- Redis Cloud alternatives: pay for the modules, or stop paying for themRedis Cloud prices itself around the module story: search, JSON, time series, vector sets, Active-Active. If you use those, the bill is buying something real. If you use Redis as a cache, a session store, or a queue, you are paying the module premium for a key-value store. Here is what each tier buys, where a flat plan fits, and when to stay.
- Build the Redis backend for a WhatsApp botConversation state with TTLs, BullMQ queues for scheduled reminders, idempotency keys for retried webhooks, and per-recipient rate limits, all on one Redis-compatible Valkey.
- Upstash alternatives: keep the client, change the URLUpstash bills Redis per command, which is brilliant for a tiny app and a meter for everything else. Every Redis and Valkey on Layerbase exposes the same REST API the @upstash/redis client speaks, and every Valkey carries a QStash-compatible queue. Here is the arithmetic, the code that does not change, and when Upstash is still the right call.