Skip to main content
You can use effect-mq with Upstash Redis. effect-mq is a background job library for Effect: you define a job once with a schema-typed payload, enqueue it from anywhere, and run it in a worker. Its Redis store (effect-mq/redis) keeps every operation atomic with a single Lua script, so you can use Upstash Redis as its storage.

Install

effect-mq targets Effect v4, which is currently published under the rc tag; @effect/platform-node@latest still targets Effect v3, so install it with the rc tag as well. The Redis store does not bundle a client; on Node.js it uses node-redis through @effect/platform-node. On Bun, install @effect/platform-bun@rc instead and use BunRedis (no extra client needed).

Usage

First, get your connection string from the TCP tab of the Connect section on your database page in the Upstash Console:
Then create the Redis store layer with that URL. It must start with rediss:// since Upstash requires TLS; node-redis picks up TLS from the scheme automatically, so no extra options are needed:
Define a job, enqueue it, and run a worker:
Provide RunnerLive to your app and the worker claims, runs, retries, and records jobs. The producer only needs StoreLive, so your API server can enqueue without depending on any handler code.

Connecting over HTTP

The setup above talks to Upstash over a TCP connection, which suits a long-running worker process. You may prefer to connect over HTTP with @upstash/redis instead when:
  • You enqueue jobs from serverless or edge functions. Vercel Functions, Cloudflare Workers, Lambda, and similar runtimes either have no TCP sockets or would open a fresh TLS connection on every cold start. @upstash/redis uses fetch, so it works anywhere and has no connection to manage.
  • You run many short-lived instances. Each TCP client holds a connection open (two for the worker, one of them for pub/sub), which adds up across many serverless invocations or autoscaled replicas. HTTP requests are stateless, so there is no connection count to watch.
effect-mq does not need a separate storage driver for this. Its Redis store talks to Effect’s client-agnostic Redis service, which only requires a send function for raw commands and a subscribe function for pub/sub wake-ups. @upstash/redis provides both (exec and subscribe), so the same store, Lua scripts, and key layout work unchanged. Install the client:
Add the following layer, which provides the Redis service over the Upstash REST API:
upstash-redis.ts
Then provide it to the store in place of NodeRedis, using the REST URL and token from the REST tab of the Connect section on your database page:
Everything else on this page stays the same: jobs, enqueue, execute, and workers all work over HTTP, including pub/sub wake-ups so idle workers pick up new jobs immediately instead of waiting for pollInterval. Because both clients run the same Lua scripts against the same keys, you can mix them under one prefix. A common split is to enqueue over HTTP from serverless functions and run the worker over TCP on a long-running process.

Billing Optimization

effect-mq workers poll Redis regularly (pollInterval), heartbeat locks on active jobs, and sweep for stalled jobs and history, even when there is no queue activity. This can incur extra costs because Upstash charges per request on the Pay-As-You-Go plan. With the introduction of our Fixed plans, we recommend switching to a Fixed plan to avoid increased command count and high costs in effect-mq use cases.