---
title: "Observe everything"
description: "Tour the Vercel Workflows dashboard, inspect every step's inputs and outputs, deploy a breaking change mid-workflow, and walk through how to debug production failures."
canonical_url: "https://vercel.com/academy/workflow-foundations/observe-everything"
md_url: "https://vercel.com/academy/workflow-foundations/observe-everything.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-10-20T22:57:37.868Z"
content_type: "lesson"
course: "workflow-foundations"
course_title: "Build Durable Workflows"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Observe everything

# Observe everything

You've been using the dashboard the entire course. Every time we placed an order, it logged what happened. Every time a step failed, it showed why. Every time the workflow waited, it told you what for.

This is the lesson where we stop treating it as scenery and use it on purpose.

Production workflows fail at 3am. The on-call engineer's first move is to open the dashboard, find the failing run, and figure out what step blew up and why. There's no SSHing into a box. There's no rummaging through logs. The dashboard is the debugger.

No new code today. Just a tour. Then you ship.

## Outcome

Walk through every view in the Workflows dashboard with intent. Know where to look when a run fails, where step inputs and outputs live, and how to confirm a workflow survived a deploy.

## Fast Track

1. Open your project's **Workflows** tab in Vercel. Find a successful run, a failed run, and a still-running run.
2. Click into each. Read the timeline, expand a step, read its inputs and outputs.
3. Place an order. While it's mid-hook, ship a code change. Confirm the existing run completes on the new build.

## Hands-on exercise

**1. The run list.**

The **Workflows** tab in your Vercel project lists every run. Each row has the workflow name, status, duration, and the time the run started.

If you don't see a healthy mix of `completed`, `failed`, and `running` runs, generate some:

- Place an order with `cardLast4: "4242"` and walk it through. → `completed`
- Place one with `cardLast4: "0000"`. → `failed`
- Place one and don't touch the kitchen UI. → `running` for 20 minutes, then `completed` (escalated)
- Place one and click **Mark ready** halfway. → `running` until you continue clicking

**2. The timeline view.**

Click into a completed run. The timeline shows every step in order, every sleep, every hook.

```
processOrder                completed   3m 12s
  ├─ chargeCard               completed   217ms
  │      input:  { id: "0a4f…", cardLast4: "4242", ... }
  │      output: { chargedAt: "2026-..." }
  │      attempts: 1
  ├─ sendOrderConfirmation    completed   389ms
  │      input:  { id: "0a4f…", email: "marge@...", ... }
  │      output: undefined
  │      attempts: 1
  ├─ acknowledgeKitchen       completed   843ms
  │      attempts:
  │        1. failed  "Kitchen printer jammed. Retrying."
  │        2. completed
  ├─ kitchen hook (kitchen:0a4f…)
  │      resumed after 2m 14s with { readyAt: "2026-..." }
  ├─ dispatchDelivery         completed   213ms
  ├─ driver-pickup hook       resumed after 35s
  ├─ markOutForDelivery       completed   18ms
  ├─ driver-delivered hook    resumed after 22s
  ├─ confirmDelivery          completed   12ms
  └─ sendReviewRequest        completed   341ms
```

The runtime preserves everything: the inputs to each step (the full `order` object), the outputs (whatever the step returned), the attempt history (every retry, with the error message), and the hook payloads (what the kitchen/driver sent).

**3. Inspect a retry.**

Find a run where `acknowledgeKitchen` retried. Expand the step. You'll see attempts listed:

```
acknowledgeKitchen      completed   843ms
  attempts:
    1. failed   208ms   Error: Kitchen printer jammed. Retrying.
    2. completed   211ms
```

Each attempt is a separate enqueue. The runtime records the failure, waits its backoff, and re-runs the step with the same inputs. The customer never noticed.

**4. Inspect a fatal failure.**

Find a run that failed because of the `0000` card. Expand `chargeCard`:

```
chargeCard            failed   208ms
  attempts:
    1. failed   FatalError: Card declined for order 0a4f...
```

One attempt. `FatalError` told the runtime not to retry. The workflow stopped immediately. Compare this to a run where you tried Resend with a deliberately bad email earlier. Same shape.

**5. Inspect a hook.**

Find a run that's still suspended on a hook. The timeline ends partway through with the hook line:

```
processOrder              running
  ├─ chargeCard               completed
  ├─ sendOrderConfirmation    completed
  ├─ acknowledgeKitchen       completed
  └─ kitchen hook (kitchen:0a4f…)
       suspended  1m 47s
```

It shows the token, how long the hook has been suspended, and that it's still waiting. No payload yet. Click into the kitchen ops UI and **Mark ready**. Refresh the dashboard. The hook line now shows `resumed`, and the workflow moves forward.

**6. Survive a deploy.**

Place an order and let it suspend on the kitchen hook.

Open `workflows/steps/send-order-confirmation.ts`. Change the email subject to add "v2" at the end. Commit. Push. Vercel deploys.

Click **Mark ready** in the kitchen UI to wake the suspended workflow.

The dashboard shows the workflow continuing on the new deploy. The `sendOrderConfirmation` step that already completed doesn't run again. The "v2" subject change applies only to future orders.

```
processOrder              completed
  ├─ chargeCard               completed   (replayed from event log)
  ├─ sendOrderConfirmation    completed   (replayed from event log, "v2" not used)
  ├─ acknowledgeKitchen       completed   (replayed from event log)
  ├─ kitchen hook             resumed     (on new deploy)
  ├─ dispatchDelivery         completed   (executed on new deploy)
  ...
```

That's the durability promise. Mid-flight workflows survive deploys. Their original timeline is sacred.

## Try It

Open a fresh tab and place ten orders. Use different combinations:

- Some with `4242`, some with `0000`
- Some you walk through the kitchen and driver UIs
- Some you ghost the kitchen for the full timeout
- Some you redeploy mid-suspension

Then go to the Workflows tab and look at the run list. You should see a mix of completed, failed, and escalated runs. Pick three at random. For each, predict what the timeline will look like before you click in. Then click in and check.

If you can do this exercise comfortably, you can debug a Workflow SDK production incident.

\*\*Note: What you can do now\*\*

You can write durable workflows that sequence steps, wait for real-world events with hooks, time out gracefully, retry on flakes, fail fast on unrecoverable errors, survive deploys, and observe every step in production. That's the entire vocabulary.

## Commit

Nothing to commit. This lesson is exploration.

## Done-When

- [ ] You've walked through completed, failed, and running runs in the dashboard
- [ ] You've expanded a step and read its inputs, outputs, and attempt history
- [ ] You've inspected a hook in `suspended` and `resumed` states
- [ ] You've shipped a code change mid-workflow and watched the existing run finish on the new build

## Solution

No code in this lesson. The skill is the lesson.

You started this course with `setTimeout` and a database table. You're ending it with `await sleep("7 days")` and a dashboard. Same problem, different vocabulary, an order of magnitude less code.

Go ship a workflow.


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
