vqueue: Scheduled HTTP Webhooks on Your Own Valkey
Short version: vqueue is an HTTP webhook queue that runs on the Valkey database you already have on Layerbase Cloud, and it implements the API surface the open-source @upstash/qstash client expects. Point that client at your own database, keep your publisher and receiver code, and stop paying a second vendor for the queue. It is free regardless of how many messages you publish, because the Valkey underneath it is the thing you are already paying for.
We just shipped vqueue, a free HTTP webhook queue layered on top of every Layerbase Cloud Valkey instance. If your app already uses @upstash/qstash to schedule webhooks, you can point it at your own Layerbase database and stop paying a second vendor for the same queue.
The Layerbase CLI (formerly SpinDB) (what is the Layerbase CLI?) is the local CLI Layerbase ships for spinning up Valkey on your laptop in 30 seconds. vqueue is the cloud-side product surface, not the CLI, but the same Valkey runs in both places.
The problem
Real apps need more than a database. Almost every web app or serverless project that hits production also wants:
- A cache (Valkey or Redis)
- A background job worker (BullMQ on top of Redis, or a managed queue)
- Scheduled HTTP delivery so a Vercel or Cloudflare function can say "fire this webhook in 30 seconds" without holding a long-running connection
Today most teams pay one vendor for Valkey, a second for managed queues. The schemas, billing, and dashboards never line up. The cache and the queue are on different infrastructure even though they both want Redis-protocol storage underneath.
What vqueue is
vqueue is a small Hono route on Layerbase Cloud that implements the HTTP API surface the open-source @upstash/qstash client expects, backed by the Valkey instance you already provisioned. Endpoints:
POST /v2/batchfor an array of message publishes (this is what@upstash/qstashbatchJSON()calls under the hood)POST /v2/publish/<destination-url>for a single message
Each delivery carries an Upstash-Signature JWT signed with HS256, identical to the format that the @upstash/qstash Receiver.verify() call accepts. Drop the env vars from your Layerbase Valkey detail page into your app and the existing client code routes through your database with zero changes.
VQUEUE_URL=https://your-db-name-queue.cloud.layerbase.dev
VQUEUE_TOKEN=<your database password>
VQUEUE_CURRENT_SIGNING_KEY=<derived; shown in the dashboard>Try it locally with the Layerbase CLI first
You can build the receiver side and signature verification on your laptop before touching the cloud at all. Spin up a local Valkey instance:
npm i -g layerbase
lbase create my-queue --engine valkey --start --connectConnection string:
lbase url my-queue
# redis://default:<password>@127.0.0.1:6379/0Build the receiver locally using the same @upstash/qstash client library. When you're ready to go live, provision a Valkey on Layerbase Cloud and swap the env vars over.
Publisher example
import { Client } from '@upstash/qstash'
const queue = new Client({
baseUrl: process.env.VQUEUE_URL,
token: process.env.VQUEUE_TOKEN,
})
await queue.batchJSON([
{
url: 'https://your-app.example.com/api/jobs/send-email',
body: { to: 'you@example.com' },
},
])Receiver example
import { Receiver } from '@upstash/qstash'
const receiver = new Receiver({
currentSigningKey: process.env.VQUEUE_CURRENT_SIGNING_KEY!,
nextSigningKey: process.env.VQUEUE_NEXT_SIGNING_KEY ?? '',
})
export async function POST(req: Request) {
const rawBody = await req.text()
const signature = req.headers.get('upstash-signature') ?? ''
const isValid = await receiver.verify({
signature,
body: rawBody,
url: 'https://your-app.example.com/api/jobs/send-email',
})
if (!isValid) return new Response('bad signature', { status: 403 })
// ...do the work
}That's it. Same code shape you'd write against any @upstash/qstash-compatible endpoint; just a different URL and a different signing key.
What's in v1
POST /v2/batch(the canonical publish path used bybatchJSON())POST /v2/publish/<destination>for single-message parity- Outbound HS256-JWT signature compatible with
Receiver.verify() Upstash-Forward-*header passthrough- Backed by the Valkey instance you already pay for; free regardless of how many messages you publish
What's coming
- Scheduled delivery (
Upstash-Delay) - Dead-letter queue inspection
- Workflow compatibility layer on top of vqueue
- Dashboard view of in-flight and recently-delivered messages
For now jobs fire immediately and best-effort with logged failures. That covers the most common use shape (fire-and-forget webhook delivery, async background work, event fan-out), which is roughly 80% of why teams reach for a managed queue.
Useful Layerbase CLI commands
# Spin up a fresh Valkey for development
lbase create dev-queue --engine valkey --start --connect
# Get the connection string
lbase url dev-queue
# Stop it when you're done; the data is preserved
lbase stop dev-queue
# Start it again later
lbase start dev-queueThe Layerbase CLI supports 21 database engines with the same install-and-run workflow, so the same project that uses vqueue against a Valkey can also pull a local Postgres, ClickHouse, or libSQL the same way.
FAQ
Do I have to rewrite my code to use vqueue?
No. vqueue implements the HTTP endpoints @upstash/qstash calls, and every delivery carries an Upstash-Signature JWT signed with HS256 in the format Receiver.verify() accepts. Swap three environment variables and your existing publisher and receiver keep working.
What does vqueue cost?
Nothing beyond the Valkey instance it runs on. There is no per-message charge, no separate signup, and no second bill, because the storage underneath is the database you already provisioned.
Which endpoints does v1 implement?
POST /v2/batch, which is what batchJSON() calls under the hood, and POST /v2/publish/<destination> for single-message parity. Plus the outbound HS256 JWT signature and Upstash-Forward-* header passthrough.
Can I schedule a delivery for later?
Not yet. Jobs fire immediately and best-effort today, with failures logged. Scheduled delivery via Upstash-Delay, dead-letter queue inspection, a workflow compatibility layer, and a dashboard view of in-flight messages are what is next.
Can I develop against it locally?
Yes, and it is the cheapest way to build the receiver side. Start a local Valkey with the Layerbase CLI, write the receiver and the signature verification against the same @upstash/qstash library, then swap the environment variables when you go live.
Where do the environment variables come from?
Every Valkey database on Layerbase Cloud shows a vqueue block on its detail page with VQUEUE_URL, VQUEUE_TOKEN, and VQUEUE_CURRENT_SIGNING_KEY ready to copy. The block only appears on engines where it means something.
Where to find the env vars
Every Layerbase Cloud Valkey database now shows a vqueue block on its detail page with VQUEUE_URL, VQUEUE_TOKEN, and VQUEUE_CURRENT_SIGNING_KEY ready to copy. The block is hidden on non-eligible engines so you only see it where it makes sense.
Free with any Valkey instance, no separate signup, no second bill. If you're already running @upstash/qstash against another provider, swap the env vars and ship.
Keep reading
- Valkey 9 on Layerbase Cloud: what you get, and what 9.1 will addNew Valkey databases on Layerbase run 9.0, and since the August security wave the build is 9.0.5. Here is what actually shipped in Valkey 9, which of it a single managed instance benefits from, what 9.1 added, and what happens to databases already on 8.0 (nothing).
- 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.
- 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.
- We put the Postgres write-ahead log on object storage. We did not put the database there.Databricks rebuilt Postgres so that object storage is the database. We shipped a much smaller thing: the write-ahead log leaves the box continuously, the live database stays on local disk. Here is the whole design, the two bugs that taught us the most, and an honest account of what this architecture does not buy.