Part 1
Why a step function
After a crash, a deploy or a day waiting for a person, the pipeline should resume at the step that was interrupted, not at the top.
Study first
- Durable execution: a function is re-run from the top after every pause or failure; steps already recorded return their saved result instead of running again. A step's result must be JSON, and a step's side effects can run twice when a result was not recorded, so each write that must not repeat is a step of its own.
- Inngest's pieces: a client, events with a name and data, functions with triggers (an event or a cron),
step.runfor work,step.waitForEventfor a pause,step.sleepfor time; the engine calls the app's serve route to run each step. - Local development: the dev server (
inngest-cli dev -u <app>/api/inngest) is the engine on the machine, with a dashboard of runs atlocalhost:8288.
Build
pnpm add inngest,pnpm add -D inngest-cli @inngest/test. pnpm runs no package's install script unless listed, andinngest-cli's script fetches its binary, so it goes underonlyBuiltDependenciesinpnpm-workspace.yaml.src/inngest/client.ts:new Inngest({ id: "workbot", eventKey, signingKey, isDev: !signingKey }), keys fromconfig. Inngest's own switch isINNGEST_DEV=1orisDev: true; this build's rule is that no signing key means dev mode, against the dev server.src/inngest/events.ts:eventType("document/received", { schema })with a Zod schema,document/reviewedwith the decision and corrected fields,reminders/requested.src/app/api/inngest/route.ts:export const { GET, POST, PUT } = serve({ client, functions }). Inroute.test.ts, callGET(new NextRequest(url), { params: Promise.resolve({}) })and expect status 200 andfunction_count: 3in the JSON (the workflow, its failure handler and the reminders): the engine's introspection of the app.pnpm inngest: the dev server pointed at the app;INNGEST_EVENT_KEYandINNGEST_SIGNING_KEYin.env.examplefor Inngest Cloud.
Done when
pnpm test src/app/api/inngestpasses, and withpnpm devandpnpm inngestrunning,localhost:8288/functionslistsdocument-approval, its failure handler andreminders.
Technical notes
- The serve route is the only route not written by this repository: the SDK's handler, listed as the exception in
src/app/api/CLAUDE.md. - Dev mode is decided in code, by the absence of a signing key, rather than by
INNGEST_DEVin the environment, soconfig.tsstays the one module that readsprocess.envand the tests run in dev mode without setup. - On Vercel, the same route serves Inngest Cloud: install Inngest's Vercel integration, which sets
INNGEST_EVENT_KEYandINNGEST_SIGNING_KEYin the project and syncs the functions on each deploy. A run that exhausts its retries is marked failed in the dashboard and raises aninngest/function.failedevent;onFailureon the function is the handler for it, and an alerting function can trigger on the same event. There is no separate dead-letter queue to drain.

