Quick start

In this tutorial you will add Inngest to a Next.js app to see how easy it can be to build complex workflows.

Inngest makes it easy to build, manage, and execute reliable workflows. Some use cases include scheduling drip marketing campaigns and payment flows, or chaining LLM interactions.

By the end of this ten-minute tutorial you will:

  • Set up and run Inngest on your machine.
  • Write your first Inngest function.
  • Trigger your function from code and Inngest Dev Server.

Let's get started!

Choose Next.js version

Choose your preferred Next.js version for this tutorial:

Before you start: choose a project

In this tutorial you can use any existing Next.js project, or you can create a new one.

Instructions to create a new Next.js project

Run the following command in your terminal to create a new Next.js project:

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

Open the chosen project in your code editor.

Next, start your Next.js app in development mode by running:

npm run dev

Now you can add Inngest to your project!

1. Install Inngest

With the Next.js app now running running open a new tab in your terminal. In your project directory's root, run the following command to install Inngest SDK:

npm install inngest

2. Run Inngest Dev Server

Next, start the Inngest Dev Server, which is a fast, in-memory version of Inngest where you can quickly send and view events events and function runs:

npx inngest-cli@latest dev
You should see a similar output:
$ npx inngest-cli@latest dev

12:38PM INF runner > starting event stream backend=inmemory
12:38PM INF executor > starting queue backend=inmemory
12:38PM INF devserver > autodiscovering locally hosted SDKs
12:38PM INF executor > service starting
12:38PM INF coreapi > service starting
12:38PM INF devserver > service starting
12:38PM INF executor > subscribing to function queue
12:38PM INF runner > starting queue backend=inmemory
12:38PM INF coreapi > starting server addr=
12:38PM INF api > starting server addr=
12:38PM INF runner > initializing scheduled messages len=0
12:38PM INF runner > service starting
12:38PM INF runner > subscribing to events topic=events

        Inngest Dev Server online at, visible at the following URLs:

          - (http://localhost:8288)

In your browser open http://localhost:8288 to see the development UI where later you will test the functions you write:

Inngest Dev Server screen with no events recorded

3. Create an Inngest client

Inngest invokes your functions securely via an API endpoint at /api/inngest. To enable that, you will create an Inngest client in your Next.js project, which you will use to send events and create functions.

Make a new directory next to your app directory (for example, src/inngest) where you'll define your Inngest functions and the client.

In this directory create an Inngest client:


import { Inngest } from "inngest";

// Create a client to send and receive events
export const inngest = new Inngest({ id: "my-app" });

Next, you will set up a route handler for the /api/inngest route. To do so, create a file inside your app directory (for example, at src/app/api/inngest/route.ts) with the following code:


import { serve } from "inngest/next";
import { inngest } from "../../../inngest/client";

// Create an API that serves zero functions
export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [
    /* your functions will be passed here later! */

4. Write your first Inngest function

In this step, you will write your first reliable serverless function. This function will be triggered whenever a specific event occurs (in our case, it will be test/hello.world). Then, it will sleep for a second and return a "Hello, World!".

Define the function

To define the function, use the createFunction method.

The createFunction method takes three objects as arguments:

  • Configuration: id is required and it is the default name that will be displayed on the Inngest dashboard to refer to your function. You can also specify additional options such as concurrency, rateLimit, retries, or batchEvents, and others.
  • Trigger: event is the name of the event that triggers your function. Alternatively, you can use cron to specify a schedule to trigger this function.
  • Handler: the function that is called when the event is received. You can also specify additional options such as invoking other functions from inside this function or logging data.

Inside your src/inngest directory create a new file called functions.ts where you will define Inngest functions. Add the following code:


import { inngest } from "./client";

export const helloWorld = inngest.createFunction(
  { id: "hello-world" },
  { event: "test/hello.world" },
  async ({ event, step }) => {
    await step.sleep("wait-a-moment", "1s");
    return { event, body: "Hello, World!" };

Add the function to serve()

Next, import your Inngest function in the routes handler (src/app/api/inngest/route.ts) and add it to the serve handler so Inngest can invoke it via HTTP:


import { serve } from "inngest/next";
import { inngest } from "../../../inngest/client";
import { helloWorld } from "../../../inngest/functions";

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [
    helloWorld, // <-- This is where you'll always add all your functions

👉 Note that you can import serve() for other frameworks and the rest of the code, in fact, remains the same — only the import statement changes (instead of inngest/next, it would be inngest/astro, inngest/remix, and so on).

Now, it's time to run your function!

5. Trigger your function from the development UI

Inngest is powered by events.

It is worth mentioning here that an event-driven approach allows you to:

  • Trigger one or multiple functions from one event.
  • Store received events for a historical record of what happened in your application.
  • Use stored events to replay functions when there are issues in production.
  • Interact with long-running functions by sending new events (cancel, wait for input, and other).

You will test your first event in two ways: by sending it directly to the Inngest UI, and then by triggering it from code.

With your Next.js and Inngest Dev Servers running, head over to Inngest Dev Server (http://localhost:8288):

Inngest Dev Server screen with no events recorded

To send a test event, click on “Test Event” in the top right corner:

Inngest Dev Server screen with no events recorded and the test button highlighted

In the popup console, add the event name (which you defined in the createFunction method earlier) and some test metadata like an email address and press the "Send Event" button:

  "name": "test/hello.world",
  "data": {
    "email": "test-user@example.com"
Event console with test data

The event is sent to Inngest (which is running locally) and automatically executes your function in the background! You can see the new function run logged in the stream tab:

Inngest Dev Server screen with one event recorded

When you click on the run, you will see more information about the event such as which function was triggered, its payload, output, and timeline:

Event details popup

In our case, the event triggered the hello-world function, which did sleep for a second and then returned "Hello, World!". No surprises here, that's what we expected!

Event details popup indicating that hello-world function ran, that it slept for 1s, and that the correct body was returned

A handy little trick: if your event behaved in an odd way, you can either replay it or edit and replay it. Replaying a function can be really helpful in debugging the function errors locally. To try it, click on the "Replay" button in the top center:

Event details popup with replay button highlighted

After the event was replayed, there are two events recorded in the dashboard:

Inngest Dev Server screen with two events recorded

Now you will trigger an event from inside your app.

6. Trigger from code

To run functions reliably in your app, you'll need to send an event to Inngest. Once the event is received, it is forwarded to all functions that listen to it.

To send an event from your code, you can use the Inngest client's send() method.

Note that with the send method used below you now can:

  • Send one or more events within any API route.
  • Include any data you need in your function within the data object.

In a real-world app, you might send events from API routes that perform an action, like registering users (for example, app/user.signup) or creating something (for example, app/report.created).

You will now send an event from the “hello” Next.js API function. To do so, create a new API handler at the src/app/api/hello/route.ts file:


import { NextResponse } from "next/server";
import { inngest } from "../../../inngest/client"; // Import our client

// Opt out of caching; every request should send a new event
export const dynamic = "force-dynamic";

// Create a simple async Next.js API route handler
export async function GET() {
  // Send your event payload to Inngest
  await inngest.send({
    name: "test/hello.world",
    data: {
      email: "testFromNext@example.com",

  return NextResponse.json({ name: "Hello Inngest from Next!" });

👉 Note that we use "force-dynamic" to ensure we always send a new event on every request. In most situations, you'll probably want to send an event during a POST request so that you don't need this config option.

Every time this API route is requested, an event is sent to Inngest. To test it, open http://localhost:3000/api/hello (change your port if your Next.js app is running elsewhere). You should see the following output: {"name":"Hello Inngest from Next!"}

Black screen with the JSON statement

If you go back to the Inngest Dev Server, you will see this new event appear there as well:

Inngest Dev Server screen with three events recorded

However, what happens if you send a different event? Let's see! Change test/hello.world to test/hello.bizarro.world and refresh http://localhost:3000/api/hello. You will see that the event was sent and received:

Inngest Dev Server screen with four events recorded, last one being 'test/hello.bizarro.world' with no functions called

... but no functions were triggered because there is not a single function in your app that is listening to such a bizarre event:

Event details for the last event where it's clear that while the event was recorded, no function was called

And - that's it! You now have learned how to create Inngest functions and you have sent events to trigger those functions. Congratulations 🥳

Next Steps

To continue your exploration, feel free to check out: