Upstash Workflow Implementation Guide
SkillDev toolsGuides your agent through building reliable background job pipelines with batching, previews, and retry-safe steps.
Use Upstash Workflow Implementation Guide in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Upstash Workflow Implementation Guide and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Upstash Workflow Implementation Guide skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
About this skill
Use for Upstash Workflow/QStash handlers, triggers, durable steps and async fan-out.
What this skill tells your AI
The instructions your AI receives, as published by lobehub/lobehub in .agents/skills/upstash-workflow/SKILL.md and read by ahel’s review.
Standard patterns for implementing Upstash Workflow + QStash async workflows in the LobeHub codebase.
🎯 The Three Core Patterns
Every workflow in LobeHub combines these three patterns. They exist because the platform constrains you in three ways: rate limits make blind fan-out dangerous, step limits cap a single workflow's size, and idempotency demands that retries don't double-process.
- 🔍 Dry-Run Mode — get statistics without triggering actual execution
- 🌟 Fan-Out Pattern — split large batches into smaller chunks for parallel processing
- 🎯 Single Task Execution — each workflow execution processes exactly ONE item
Architecture Overview
All workflows follow the same 3-layer architecture:
Layer 1: Entry Point (process-*)
├─ Validates prerequisites
├─ Calculates total items to process
├─ Filters existing items
├─ Supports dry-run mode (statistics only)
└─ Triggers Layer 2 if work is needed
Layer 2: Pagination (paginate-*)
├─ Handles cursor-based pagination
├─ Implements fan-out for large batches
├─ Recursively processes all pages
└─ Triggers Layer 3 for each item
Layer 3: Single Task Execution (execute-* / generate-*)
└─ Performs actual business logic for ONE item
Real examples in this codebase: topicAutoSummary, agentEvalRun — see references/examples.md.
The Three Patterns in 60 Seconds
1. Dry-Run Mode
Short-circuit Layer 1 before any side effects so callers can preview what would happen:
if (dryRun) {
return {
...result,
dryRun: true,
message: `[DryRun] Would process ${itemsNeedingProcessing.length} items`,
};
}
Use case: check how many items will be processed before committing.
2. Fan-Out Pattern
Layer 2 splits oversized batches into chunks and recursively re-triggers itself with each chunk. This avoids hitting workflow step limits when one page contains too many items:
const CHUNK_SIZE = 20;
if (itemIds.length > CHUNK_SIZE) {
const chunks = chunk(itemIds, CHUNK_SIZE);
await Promise.all(
chunks.map((ids, idx) =>
context.run(`workflow:fanout:${idx + 1}/${chunks.length}`, () =>
WorkflowClass.triggerPaginateItems({ itemIds: ids }),
),
),
);
}
Defaults: PAGE_SIZE = 50 (items per page), CHUNK_SIZE = 20 (items per fan-out chunk).
3. Single Task Execution
Layer 3 always processes exactly one item per invocation. Parallelism comes from Layer 2 fanning out to many Layer 3 invocations, controlled by flowControl:
app.post(
'/execute-item',
serve<ExecutePayload>(
async (context) => {
const { itemId } = context.requestPayload ?? {};
if (!itemId) return { success: false, error: 'Missing itemId' };
const item = await context.run('workflow:get-item', () => getItem(itemId));
const result = await context.run('workflow:execute', () => processItem(item));
await context.run('workflow:save', () => saveResult(itemId, result));
return { success: true, itemId, result };
},
{
flowControl: { key: 'workflow.execute', parallelism: 10, ratePerSecond: 5 },
},
),
);
File Structure
src/app/(backend)/api/workflows/
└── [[...route]]/route.ts # Single catch-all — forwards every request to the Hono app below
apps/server/src/router-hono/workflows/
├── index.ts # Mounts each workflow's Hono app at /api/workflows/{workflow-name}
└── {workflow-name}/
├── index.ts # Hono app — one `app.post('/{layer}', serve(handler, options))` per layer
├── dispatch.ts / paginate-*.ts # Layer 1 + 2 handler(s) — entry point, dry-run, pagination, fan-out
└── execute.ts / execute-*.ts # Layer 3 handler — single-task execution
apps/server/src/workflows/
└── {workflowName}/
└── index.ts # Workflow class — static trigger*() methods that POST to the routes above
Every layer is a handler mounted on a per-workflow Hono app under apps/server/src/router-hono/workflows/; the Next.js route under src/app only dispatches into it.
Where to Go Next
Pick the reference that matches what you're doing:
| You want to... | Read |
|---|---|
| Write the Workflow class + 3 routes from scratch | references/implementation.md |
| Tune flowControl, error handling, logging, testing | references/best-practices.md |
| See two real workflows end-to-end | references/examples.md |
| Deploy on lobehub-cloud (re-exports, cloud-only ops) | references/cloud.md |
Environment Variables
# Required for all workflows
APP_URL=https://your-app.com # Base URL for workflow endpoints
QSTASH_TOKEN=qstash_xxx # QStash authentication token
# Optional (for custom QStash URL)
QSTASH_URL=https://custom-qstash.com
Checklist for New Workflows
Planning
- Identify the entity to process (users, agents, items, …)
- Define the per-item business logic
- Determine filtering logic (Redis cache, database state, …)
Implementation
- Define payload types with TypeScript interfaces
- Create workflow class with static trigger methods
- Layer 1: entry point with dry-run support
- Layer 1: filtering logic to avoid duplicate work
- Layer 2: pagination with fan-out
- Layer 3: single-task execution (ONE item per run)
- Configure appropriate
flowControlfor each layer - Consistent logging with workflow prefixes
- Validate all required payload parameters
- Unique
context.run()step names
Quality & Deployment
- Return consistent response shapes
- Configure cloud deployment (
references/cloud.mdif on lobehub-cloud) - Write integration tests (
dryRunpath + full path) - Smoke-test with dry-run first
- Test with a small batch before full rollout
Additional Resources
Advanced
- Item type
- skill
- Key
upstash-workflow-lobehub- Source
- github.com/lobehub/lobehub
Related picks
Skill · mattpocock
The pick for TypeScripttypescript-pro
Skill · jeffallan
The pick for TypeScriptclerk-nextjs-patterns
Skill · clerk
The pick for Next.jslogs-nextjs
Skill · posthog
The pick for Next.jsnodejs-backend-patterns
Skill · wshobson
The pick for Noderun-node-tests
Skill · hiroro-work
The pick for Node