vercel-labs/workflow-publish-subscribe: Pub/Sub That Refuses to Be a Black Box

A durable workflow demo that turns message delivery into a visible, resumable sequence, then maps execution back onto the code so you can see exactly what happened and where.

8 min read • View on GitHub • More from vercel-labs

A mailbox-like publishing station feeds envelopes into a row of transparent chambers, while a tracing arm draws a line back to a pinned source code page. The scene explains how each delivery becomes observable, durable execution instead of a hidden queue job.
The demo treats execution like something you can inspect in motion, not something you only infer from logs.
Key Takeaways

The backend that shows its work

Most Pub/Sub demos stop at delivery. This one does something more interesting: it publishes a message, streams the workflow state back to the browser, and highlights the exact source lines that are executing. The result feels less like a queue demo and more like a backend with a built-in stage light.

That matters because backend systems are usually legible only after the fact. Here, the app is legible while it runs. The workflow does not just complete. It explains itself.

A close-up of a code editor page split into source on the left and live execution on the right. One highlighted line is tied by a taut thread to an active subscriber in a delivery queue, while completed steps are stamped and locked, showing how runtime state maps back to source lines.
The workbench ties runtime state to source locations, which turns tracing into a visual relationship instead of a separate tool.

Why Pub/Sub is usually a black box

Traditional queues are good at one thing: moving work from A to B. The trouble starts when you need to know what happened inside that trip. Did a subscriber fail before the commit? Did a retry duplicate work? Which event is stuck, and why?

ModelWhere state livesRetriesObservabilityDeveloper writesOperational overheadBest fit
Traditional Pub/SubMostly outside the app, in queue infrastructureUsually added around the queue, often with dead-letter handlingLogs, metrics, and ad hoc tracingHandlers plus retry glueMedium to highSimple async delivery at scale
TemporalIn the workflow engineBuilt into durable executionStrong execution history and toolingWorkflow code with engine semanticsHighComplex long-running orchestration
AWS Step FunctionsIn AWS state machine definitionsNative state transitions and retriesVisual graph plus cloud telemetryJSON or visual state machineMediumCloud-native orchestration on AWS
InngestIn the platform and event graphManaged by the event systemGood event visibility and replayFunction handlers and event triggersLow to mediumEvent-driven serverless apps
vercel-labs/workflow-publish-subscribeInside the workflow code itselfCheckpointed by durable stepsSSE stream plus source-line highlightingJavaScript workflow with "use workflow" and "use step"LowLegible durable Pub/Sub demos and teaching

The interesting part is not that this repo replaces every queue pattern. It does not. The interesting part is that it collapses delivery, retries, and traceability into one readable flow. The backend is not hidden behind an ops console. It is embedded in the code path itself.

Workflow Development Kit brings durability, reliability, and observability to async JavaScript so you can build apps and AI agents that suspend, resume, and maintain state with ease.

Pauline P. Narvas (@pawlean), Vercel Community · Vercel Community announcement

What the workflow actually does

At the center of the repo is publishSubscribeFlow. It reads like ordinary async JavaScript, but the directives change the game. "use workflow" marks the function as durable, and "use step" turns important phases into checkpoints that can resume after interruption.

export async function publishSubscribeFlow(input: PublishSubscribeInput) {
  "use workflow";

  const subscription = await registerSubscription(input);
  const targets = await filterSubscribers(subscription.topic, input.payload);
  const delivered = await deliverToSubscribers(targets, input.payload);

  return summarizeDelivery(delivered);
}

async function deliverToSubscribers(subscribers, payload) {
  "use step";
  // durable delivery work happens here
}

That structure matters because the workflow is not a single fragile function call. It is a sequence of durable phases. If delivery fails halfway through, completed steps stay completed. The next run resumes from the last checkpoint instead of replaying the whole story.

The system closes the loop between code, runtime, and UI so the browser can explain execution as it happens.

The trick: code that streams its own execution

The most distinctive move in the repo is not the workflow runtime. It is the feedback loop. The app reads its own workflow file, builds a line map, then uses Server-Sent Events to stream execution events into the browser so the current phase can be highlighted against the source.

That makes the UI more than a viewer. It becomes a guided reading surface for the backend. You are not just watching subscribers get processed. You are watching the exact lines that process them light up in context.

const workflowSource = readFileSync('workflows/publish-subscribe.ts', 'utf8');
const lineMap = buildWorkflowLineMap(workflowSource);

const run = await start(publishSubscribeFlow, input);
const readable = await run.getReadable();

// SSE route forwards workflow events to the browser
for await (const chunk of readable) {
  controller.enqueue(encodeSSE(chunk));
}

That is why this demo feels educational instead of decorative. It does not merely visualize state. It binds state back to source. The browser becomes a live annotation layer for the code itself.

Why this is different from queues and orchestrators

The comparison is subtle. Traditional queues optimize for transport. Orchestrators optimize for control flow. This repo optimizes for legibility. The workflow is still durable, but the product goal is to make durability understandable to a human looking at the screen.

SystemCore ideaMain strengthMain trade-off
Queue-based Pub/SubPush messages through a reliable pipeSimple, scalable transportExecution is harder to observe and reconstruct
TemporalExternal durable engine runs the workflowPowerful histories and retriesMore infrastructure and a heavier conceptual model
AWS Step FunctionsManaged state machine orchestrationClear cloud-native transitionsWorkflow logic is split between code and service
InngestEvent-driven durable functionsFast path to serverless reliabilityStill a platform layer between code and runtime
This repoWorkflow code is the boundary and the debuggerCode, state, and tracing stay tightly coupledBest suited to demos, teaching, and developer experience exploration

The point is not to pick a universal winner. The point is to notice the design bet. This repo treats observability as part of the workflow contract. That is a different promise from most queue systems, and a cleaner promise than many orchestration stacks make to developers.

Running async jobs have been one of the common issues when using serverless paradigms as jobs reference persistent state and serverless is stateless. Instead of cloning competitors, Vercel invented an entirely new approach around building long-running tasks.

Yangshun Tay, AI Front End Engineer · LinkedIn post on Workflow DevKit

What Vercel is really testing here

This repo is a small demo with a larger thesis: durable JavaScript on serverless infrastructure should not feel like a compromise. The app suggests a future where reliability, replay, and observability are not bolted on after deployment. They are the way the code runs.

That is also why the project feels a little provocative. It makes a backend pattern behave like a teaching tool. For teams building event-driven systems, that is more than a nice demo. It is a different mental model for how software should explain itself.