TypeScript SDK v4 is now available! See what's new

Next.js Quick Start

This tutorial walks you through adding Inngest to a Next.js app. By the end, you'll have a working function that runs in the background, triggered by an event, with full visibility into its execution in the Inngest Dev Server.

The guide takes about ten minutes. You'll need an existing Next.js project, or you can create one as part of the setup below.


Before you start

You can use any existing Next.js project for this tutorial. If you don't have one, create a new one by running:

npx create-next-app@latest --ts --eslint --tailwind --src-dir --app --import-alias='@/*' inngest-guide

Once your project is ready, start the development server. If you're using the v4 SDK, set INNGEST_DEV=1 so your app connects to the local Dev Server instead of Inngest Cloud:

INNGEST_DEV=1 npm run dev

You can also add INNGEST_DEV=1 to your .env.local file so you don't need to pass it inline every time.


1. Install Inngest

In a new terminal tab, run the following in your project's root directory:

npm install inngest

2. Run the Inngest Dev Server

The Inngest Dev Server is a local environment where you can send events, trigger functions, and inspect runs in real time. Start it with:

npx inngest-cli@latest dev

Open http://localhost:8288 to see the Dev Server UI. You'll use this to monitor function runs as you work through the tutorial.


3. Create an Inngest client

Inngest invokes your functions through an API endpoint at /api/inngest. The serve handler at this endpoint lets Inngest discover which functions your app has and execute them when triggered. To set that up, you need an Inngest client and a serve route handler.

// src/inngest/client.ts
import { Inngest } from "inngest";

export const inngest = new Inngest({ id: "my-app" });

For the App Router, you also need to create a route handler that serves the Inngest API:

src/app/api/inngest/route.ts
import { serve } from "inngest/next";
import { inngest } from "../../../inngest/client";

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [],
});

4. Write your first function

In this step you'll write a function that processes a task in the background. The function waits for a trigger event, runs a sequence of steps, and returns a result.

This pattern is useful for anything you don't want running in a request/response cycle: sending emails, calling an AI model, processing a file upload, or chaining multiple operations together.

Define the function:

// src/inngest/functions.ts
import { inngest } from "./client";

export const processTask = inngest.createFunction(
  { id: "process-task", triggers: { event: "app/task.created" } },
  async ({ event, step }) => {
    const result = await step.run("handle-task", async () => {
      return { processed: true, id: event.data.id };
    });

    await step.sleep("pause", "1s");

    return { message: `Task ${event.data.id} complete`, result };
  }
);

Then register the function with your serve handler:

// src/app/api/inngest/route.ts
import { serve } from "inngest/next";
import { inngest } from "../../../inngest/client";
import { processTask } from "../../../inngest/functions";

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [processTask],
});

5. Trigger your function

There are two ways to trigger a function: from the Dev Server UI, or by sending an event from your app code.

From the Dev Server

Open http://localhost:8288/functions and find process-task. Click Invoke, then send a payload like this:

{
  "data": {
    "id": "task_001"
  }
}

Click Invoke Function. Switch to the Runs tab to see the execution in progress. Click into the run to see each step, its output, and the timeline.

From your app

To trigger the function from code, send an event using the inngest.send() method.

// src/app/api/create-task/route.ts
import { NextResponse } from "next/server";
import { inngest } from "../../../inngest/client";

export async function POST() {
  await inngest.send({
    name: "app/task.created",
    data: { id: "task_001" },
  });

  return NextResponse.json({ message: "Event sent" });
}

Send a request to your new endpoint:

curl -X POST http://localhost:3000/api/create-task

You'll see a new run appear in the Dev Server. In practice, you would call inngest.send() from the places in your app that send events: form submissions, webhook handlers, API routes, and so on.


Next steps

You now have Inngest running locally in a Next.js app. From here, a few directions worth exploring:

  • Configure checkpointing for serverless. v4 enables checkpointing by default, which lets multiple steps run in a single request. If you're on Vercel or another serverless platform, set maxRuntime on your client and maxDuration on your /api/inngest route to avoid timeout issues. See the Vercel deployment guide for details.
  • Deploy to production. Connect your app to Inngest Cloud and sync your functions. See the deployment guide if you're on Vercel.
  • Build a multi-step workflow. Add branching logic, retries, and parallel steps. The Inngest Functions overview covers what's available.
  • Orchestrate AI workflows. Use step.ai.wrap() to make LLM calls durable and retryable, or step.waitForSignal() to pause a workflow until a human approves an action. See the AI orchestration guide.