Skip to content

Upstash alternatives: keep the client, change the URL

9 min readUpstashRedisValkeyQueuesPricingComparison

Short version: Upstash is a very good serverless Redis with a per-command meter, and the meter is the whole question. Under a few hundred thousand commands a month it is free and you should probably stay. Past that, every cache hit is a line item, and a cache that does its job well is a cache that racks up commands. Layerbase runs Redis and Valkey behind the same REST API the @upstash/redis client already speaks, and every Valkey database carries a queue the @upstash/qstash client already speaks, so moving is a URL change on a flat plan. Solo is $5/month, Pro is $15/month, and the command count is not on the bill.

What Upstash actually is

Upstash built the thing serverless runtimes needed: Redis you can reach over HTTP from a Cloudflare Worker or a Vercel Edge Function, with no TCP socket to hold open and no connection pool to manage. The REST API is the product. The Redis underneath it is excellent, the global replication is real, and QStash turned "I need a scheduled webhook" into three lines of code. I have recommended it and I still would in the right shape.

They also won the distribution war. Vercel KV was Upstash under a wrapper, and it was folded back into Upstash in December 2024. Redis on Fly is Upstash. If you added Redis from a marketplace in the last two years, you are probably an Upstash customer whether or not you chose to be.

The shape of the bill is the thing to understand before you decide anything.

The meter

Verified 2026-09-06 from upstash.com/pricing/redis:

PlanPriceWhat you get
Free$0500K commands/month, 256 MB, 10 GB bandwidth
Pay-as-you-go$0.2 per 100K commands$0.25/GB storage after the first GB, bandwidth free to 200 GB/month then $0.03/GB, 100 GB max
Fixed 250MB$10/month250 MB, 50 GB bandwidth
Fixed 1GB$20/month1 GB, larger bandwidth allowance
Prod Pack+$200/month per databaseUptime SLA, multi-zone HA, encryption at rest, SOC 2

Free databases are archived after 30 days idle, backed up first.

The free tier is generous for what it is. 500,000 commands a month is about 11 a minute sustained, which covers a personal project comfortably. The 256 MB is plenty for sessions and rate limits.

The problem starts the moment your app gets used. A cache is only useful when it is hit constantly, and every hit is a command. Take an ordinary web app doing 20 Redis commands per request: a session lookup, a rate-limit check, a couple of cache reads, a couple of writes, some EXPIRE calls. At a million requests a month that is 20 million commands, which is $40 on pay-as-you-go plus storage. At five million requests it is $200. The fixed plans cap the exposure at a size, but a 250 MB fixed database is $10 a month for the same amount of memory a free tier gives you elsewhere.

None of this is hidden. Upstash is completely upfront about the meter, and the meter is why a tiny app is free. It is also why a successful app's Redis bill scales with success in a way its Postgres bill does not, and that mismatch is what sends people looking for alternatives.

What Layerbase does differently

Flat plans. Free is $0 with no card: 2 databases, 5 GB, 8 engines including Redis and Valkey, sleeping after 15 idle minutes and waking on connect. Solo is $5/month for 2 databases with one always-on, 10 GB, 3 branches per database, and daily backups kept for 7 days. Pro is $15/month for up to 10 databases, 25 GB, all 18 engines on Layerbase Cloud, 10 branches per database, and 30-day backups. Commands are not counted on any of them.

The same REST API. Every Redis and Valkey database on Layerbase exposes an Upstash-compatible REST endpoint alongside the normal TLS port. The Connect dialog shows a REST URL and a REST token, and the @upstash/redis client takes them without knowing the difference. @vercel/kv takes the same pair. Cloudflare Workers, Vercel Edge, and anything else that cannot open a raw socket keep working.

The same queue. Every Valkey database on Layerbase carries vqueue, an HTTP queue that implements the API surface the @upstash/qstash client expects: signed deliveries, scheduled delays, automatic retries, and a dead-letter queue you can inspect and re-enqueue from the dashboard. It is included with the database, not a second product with a second meter. The vqueue launch post has the details.

Ordinary TLS too. rediss:// on port 6379 for ioredis, redis-cli, BullMQ, and anything that prefers a socket. Same keys, same database, both doors.

Two engines, versions stated plainly. Our Redis is pinned at 7.2, the last release before Redis changed its license, and it will stay there. Our Valkey is 9.0. For new work use Valkey: same wire protocol, same clients, BSD license, and it is the engine vqueue runs on. The Redis vs Valkey post covers the fork if you want the history.

The code that does not change

This is the part I want to be precise about, because "compatible" gets said loosely.

Redis over REST, before:

ts
import { Redis } from '@upstash/redis'

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
})

await redis.set('session:42', { userId: 7 }, { ex: 3600 })
const session = await redis.get('session:42')

After:

ts
import { Redis } from '@upstash/redis'

const redis = new Redis({
  url: process.env.LAYERBASE_REST_URL!,
  token: process.env.LAYERBASE_REST_TOKEN!,
})

await redis.set('session:42', { userId: 7 }, { ex: 3600 })
const session = await redis.get('session:42')

The import, the constructor, and every call are identical. Only the two environment variables move.

Queue, before:

ts
import { Client } from '@upstash/qstash'

const qstash = new Client({ token: process.env.QSTASH_TOKEN! })

await qstash.publishJSON({
  url: 'https://example.com/api/send-receipt',
  body: { orderId: 'ord_123' },
  delay: 300,
})

After:

ts
import { Client } from '@upstash/qstash'

const queue = new Client({
  baseUrl: process.env.VQUEUE_URL!,
  token: process.env.VQUEUE_TOKEN!,
})

await queue.publishJSON({
  url: 'https://example.com/api/send-receipt',
  body: { orderId: 'ord_123' },
  delay: 300,
})

One extra constructor option, baseUrl, pointing at your own database. Receivers verify signatures the same way they did before.

Plain socket, if you want it:

ts
import Redis from 'ioredis'

const redis = new Redis(process.env.REDIS_URL!) // rediss://default:<password>@<host>.cloud.layerbase.dev:6379
await redis.set('session:42', JSON.stringify({ userId: 7 }), 'EX', 3600)

Moving the keyspace

The Upstash migration page walks the guided path: in the create flow choose Migrating from another platform, pick Upstash, and paste your management API key plus the account email. It lists your databases, you pick one, and it copies every key, type, and TTL with a non-blocking SCAN. Your Upstash database is read once and never written to. Land on Valkey if you want the queue.

By hand, the rediss:// endpoint Upstash gives every database is a normal Redis endpoint. Skip the tempting redis-cli loop, though: DUMP returns binary, a shell variable mangles it, and RESTORE rejects every key with a checksum error. A dozen lines of ioredis keep the bytes intact:

bash
npm i ioredis
SRC='rediss://default:<token>@<name>.upstash.io:6379' \
DST='rediss://default:<password>@<host>.cloud.layerbase.dev:6379' \
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, and running it twice is safe. The step-by-step version with the client swap and what to test is in Migrating from Upstash to Layerbase. Coming from a Vercel KV store instead? That is Upstash too now, and the Vercel KV alternatives post covers the extra KV_URL wrinkle.

Stay on Upstash if

Four cases where I would not move.

Your app is tiny. Under 500K commands a month, Upstash is free and always on, and it does not sleep. A free Layerbase database sleeps after 15 idle minutes and takes a moment to wake. For a hobby project that gets a visit an hour, the meter is the better deal and there is nothing to optimize.

You need global read replicas. Upstash's read regions put a replica near each edge location for a few dollars a region. That is a real feature for a globally distributed read-heavy cache, and we do not offer it. If your p99 depends on the cache being in the same region as the Worker, that is the row that decides it.

You use Upstash Vector or Search. Those are separate products on the same account. We host Qdrant, Weaviate, and Meilisearch, which cover the same jobs, but they are different APIs and moving them is a real migration, not a URL swap.

The Prod Pack is the point. If you are paying the $200 per database for the SLA, multi-zone HA, and compliance paperwork, you are buying something a $15 plan does not offer, and comparing the two prices without saying that would be dishonest.

The case for moving: your command count has become a bill, you want the queue and the cache on one thing you own, or you want a Redis with a number on it rather than a rate.

FAQ

How does Upstash pricing work?

Per command. Verified 2026-09-06, the free plan includes 500K commands a month with 256 MB, pay-as-you-go is $0.2 per 100K commands plus $0.25 per GB of storage after the first gigabyte, and fixed plans start at $10 a month for 250 MB. The Prod Pack adds $200 a month per database for the SLA and HA.

Does the @upstash/redis client work with Layerbase?

Yes. Every Redis and Valkey database on Layerbase exposes an Upstash-compatible REST endpoint with its own URL and token, shown in the Connect dialog. Point the client at them and the code does not change. @vercel/kv takes the same pair.

Is there a QStash replacement?

vqueue, which ships with every Valkey database on Layerbase and implements the API the @upstash/qstash client expects: signed deliveries, delays, retries, and a dead-letter queue in the dashboard. Add baseUrl to the client constructor and keep the rest. It is included with the database.

Should I pick Redis or Valkey?

Valkey for anything new. It is the same wire protocol and the same clients, it is BSD-licensed, and vqueue runs on it. Our Redis is pinned at 7.2, the last version before the license change, for workloads that specifically need upstream Redis.

How do I copy my data out of Upstash?

The wizard on the Upstash migration page takes a management API key and your account email, lists your databases, and copies every key, type, and TTL with a non-blocking scan. By hand, a short ioredis script that SCANs the keyspace and DUMPs and RESTOREs each key with its TTL does the same thing; the post above has it.

Is $15 a month really comparable to a per-command meter?

Not feature for feature, and the honest answer depends on volume. At 20 million commands a month the meter is $40 plus storage and a flat plan is $15. At 200K commands the meter is $0 and the flat plan is $5 if you want always-on. Do your own multiplication with your own numbers; the crossover is lower than most people expect.

The wrap-up

Upstash built the right product for serverless and priced it in the way that made it free to try. Both of those are to their credit. The meter is also why a cache that works becomes a cache that costs, and that is the moment to ask whether you want to keep renting Redis by the command.

If you do not, create a Valkey, copy the REST URL and token from the Connect dialog, and change two environment variables. The client stays. If you have data to bring, start at the Upstash migration page.