Vercel Logo

Set up the pizza tracker

Most fancy backend tools demand a setup ceremony. New CLI, new project, new runtime, new YAML file you'll never look at again. Workflow keeps it suspiciously chill.

You install one package. You change one line in next.config.ts. That's it. Your existing Next app is now capable of running durable workflows.

This lesson is mostly clicking through configuration. We'll clone the pizza tracker starter, install the SDK, and wire up the config. The interesting stuff starts in 1.2 when we write our first step. But before we can do anything, the pizza shop needs to be open for business.

Outcome

Get the pizza tracker starter running locally with the Workflow SDK installed and next.config.ts wired up. By the end you'll see the order form at http://localhost:3000.

Fast Track

  1. Clone the starter and run pnpm install.
  2. Add the workflow package: pnpm add workflow. Wrap your next.config.ts export with withWorkflow() from workflow/next.
  3. Add RESEND_API_KEY to .env.local. Run pnpm dev.

Hands-on exercise

We're working from the course starter repo. It's a Next.js 16 app with a customer order form, a kitchen ops page, a driver ops page, and an in-memory order store. Everything renders but nothing durable happens yet.

1. Install the Workflow SDK.

pnpm add workflow

2. Wrap your Next config.

The withWorkflow() helper from workflow/next is what teaches Next.js to handle the "use workflow" and "use step" directives. Without it, those directives are silently ignored.

Update next.config.ts:

next.config.ts
import { withWorkflow } from "workflow/next";
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  experimental: {},
};
 
export default withWorkflow(nextConfig);

3. (Optional) Turn on the TypeScript plugin.

If you want IntelliSense for workflow primitives, add the plugin to tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "plugins": [
      { "name": "next" },
      { "name": "workflow" }
    ]
  }
}

4. Add your Resend key.

.env.local
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxx

Grab one from resend.com/api-keys. The free tier sends from onboarding@resend.dev and works fine for the rest of the course. You don't need to verify a domain.

5. Boot it.

pnpm dev

Try It

Open http://localhost:3000. You should see Sal's Pizza order form pre-filled with Marge Pepperoni's details and a Carbonara waiting to be ordered.

Don't click the button yet. Right now /api/orders just generates a fake runId, stores the order in memory, and redirects you to a status page. No workflow is running. That's our job in the next three lessons.

Hover over the form fields. The starter already has reasonable defaults so you don't have to type Marge's address every time you test the flow. You'll be placing a lot of orders this course.

Why the wrap matters

Without withWorkflow(), your "use workflow" and "use step" directives compile down to no-ops. The wrap installs a Next.js plugin that finds those directives at build time and compiles each step into its own isolated route. Skip the wrap and you'll wonder for an hour why nothing works.

Commit

feat(setup): install Workflow SDK and wrap next.config.ts

Done-When

  • pnpm install completes without errors
  • workflow is in your package.json dependencies
  • next.config.ts wraps the export with withWorkflow()
  • .env.local contains your RESEND_API_KEY
  • pnpm dev boots and http://localhost:3000 shows the order form

Solution

next.config.ts:

next.config.ts
import { withWorkflow } from "workflow/next";
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  experimental: {},
};
 
export default withWorkflow(nextConfig);

package.json (relevant entry):

package.json
{
  "dependencies": {
    "next": "16.2.6",
    "react": "19.0.0",
    "react-dom": "19.0.0",
    "resend": "6.12.4",
    "workflow": "4.2.5"
  }
}

tsconfig.json (relevant entry):

tsconfig.json
{
  "compilerOptions": {
    "plugins": [
      { "name": "next" },
      { "name": "workflow" }
    ]
  }
}

.env.local:

.env.local
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxx

That's the entire setup. One package, one wrap, one env var. The next lesson is where we actually do something durable.

Was this helpful?

supported.