client.logs to fetch the workflow state. However, this approach is slow and expensive. A better solution is to use Upstash Realtime, which enables you to emit events from your workflow and subscribe to them in real-time on your frontend.
How It Works
Upstash Realtime is powered by Upstash Redis and provides a simple API for publishing and subscribing to events:- When you emit an event, it’s instantly delivered to live subscribers and stored for later retrieval
- Your frontend can subscribe to these events in real-time
- You can also fetch events emitted in the past
Prerequisites
- An Upstash account with:
- A QStash project for workflows
- A Redis database for Realtime
- Next.js application set up
Setup
1. Install Dependencies
2. Configure Upstash Realtime
Create a Realtime instance inlib/realtime.ts:
3. Create a Realtime Endpoint
Create an API route atapp/api/realtime/route.ts to handle Realtime connections:
4. Add the Realtime Provider
Wrap your application in theRealtimeProvider by updating your root layout at app/layout.tsx:
5. Create a Typed Client Hook
Create a typeduseRealtime hook at lib/realtime-client.ts:
Building the Workflow
1. Create the Workflow Endpoint
Create your workflow atapp/api/workflow/basic/route.ts:
- Use
realtime.channel(workflowRunId)to create a unique channel per workflow run - Emit events after each step completes
- Emit events inside
context.runsteps to ensure that they are emitted only once as the workflow executes. - Events are emitted to separate event names like
workflow.stepFinishandworkflow.runFinish
2. Create a Trigger Endpoint
Create an endpoint to trigger workflows atapp/api/trigger/route.ts:
Building the Frontend
1. Create a Custom Hook
Create a React hook to manage the Realtime subscription athooks/useWorkflowWithRealtime.ts:
- Subscribe to multiple events using the
eventsarray:["workflow.stepFinish", "workflow.runFinish"] - The hook manages both triggering the workflow and subscribing to updates
- Type-safe event handling with TypeScript
2. Use the Hook in Your Component
How It All Works Together
- User triggers workflow: The frontend calls
/api/trigger, which returns aworkflowRunId - Workflow executes: The workflow runs as a background job, emitting events at each step
- Frontend subscribes: Using the
workflowRunId, the frontend subscribes to the Realtime channel - Real-time updates: As the workflow emits events, they’re instantly delivered to the frontend via Server-Sent Events
Benefits Over Polling
Polling (client.logs) | Realtime |
|---|---|
| Slow (requires HTTP requests) | Instant (Server-Sent Events) |
| Expensive (repeated API calls) | Efficient (single connection) |
| High latency (poll interval) | Low latency (real-time) |
Full Example
For a complete working example with all steps, error handling, and UI components, check out the Upstash Realtime example on GitHub.Next Steps
- Learn about human-in-the-loop workflows with Realtime
- Explore Realtime features
- Check out Workflow configuration options