Durable Endpoints Beta

Durable Endpoints let you build or transform your API into fault-tolerant endpoints simply by wrapping your critical logic into durable steps.

Durable Endpoints behave like normal endpoints. The mental model stays the same: request, response. But each step brings you tracing, observability, and retry logic from the point of failure.

When to use Durable Endpoints

You have endpoints that fail partway through. Any endpoint with multiple steps where failure at step 3 means steps 1 and 2 were wasted work. Instead of writing try/catch logic everywhere or hoping for the best, simply wrap your code in steps and let failures resume from where they left off.

You want observability without the setup. If you want visibility into your endpoints without configuring a bunch of external services, Durable Endpoints give you that instantly.

You're already using Inngest. You can add durability to other endpoints without refactoring everything into a workflow or thinking heavily about event logic.

Quick Start

If you have a traditional endpoint:

import { NextRequest } from "next/server";

export const POST = async (req: NextRequest) => {
  const { userId, data } = await req.json();

  const user = await db.users.find(userId);
  const enriched = { ...data, account: user.accountId };

  const result = await processData(enriched);

  await sendNotification(userId, result);

  return Response.json({ success: true, result });
};

Create an Inngest client:

import { Inngest } from "inngest";
import { endpointAdapter } from "inngest/next";

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

Then, wrap your API endpoint with inngest.endpoint and move your endpoint's critical logic into step.run blocks:

import { step } from "inngest";
import { inngest } from "@/inngest/client";
import { NextRequest } from "next/server";

export const POST = inngest.endpoint(async (req: NextRequest) => {
  const { userId, data } = await req.json();

  // Step 1: Validate and enrich the data
  const enriched = await step.run("enrich-data", async () => {
    const user = await db.users.find(userId);
    return { ...data, account: user.accountId };
  });

  // Step 2: Process the enriched data
  const result = await step.run("process", async () => {
    return await processData(enriched);
  });

  // Step 3: Send notification
  await step.run("notify", async () => {
    await sendNotification(userId, result);
  });

  return Response.json({ success: true, result });
});

If process fails, the endpoint will retry from that step. enrich-data won't re-run.

Read the Durable Endpoint TypeScript SDK Reference for more detailed usage information.

Using Steps

Durable Endpoints support all the same step methods as Inngest functions. See the Steps documentation for the full reference:

Requesting a Durable Endpoint

Durable Endpoints behave like regular API endpoints on the success path. You can request them from your front-end (or back-end) using fetch() or your favorite query or http library.

When a failure triggers retries or long-running steps like step.waitForEvent() are used, a Durable Endpoint redirects to a separate endpoint that waits for the call to finish.

By default, this is an endpoint either in the Inngest Dev Server or Inngest Cloud, depending on which environment you're in, but inngest.endpointProxy() can be used to create your own URL to satisfy CORS constraints when the endpoint is used from browsers.

// When setting the `endpointAdapter`, use `.withOptions()` to set more config
const inngest = new Inngest({
  id: "my-app",
  endpointAdapter: endpointAdapter.withOptions({
    asyncRedirectUrl: "/wait",
  }),
});

// Then create the route with `inngest.endpointProxy()`
Bun.serve({
  port: 3000,
  routes: {
    "/process": ...,
    "/wait": inngest.endpointProxy(),
  },
});

Requests will now be redirected to /wait.

SDK Support

SDKSupportVersion
TypeScript✅ Beta>= 3.x (with endpointAdapter)
Go>= v0.14.0

Limitations

Durable Endpoints is currently in beta. The following limitations apply:

  • Flow control is not supported — Features like concurrency limits and rate limiting are not available for Durable Endpoints
  • POST body is not yet supported — Prefer using query strings for passing data. POST body support is coming soon
  • Standard HTTP responses only — Durable Endpoints should return a standard HTTP response, not an SSE stream

Examples

The Durable Endpoints example page provides practical pattern examples such as parallel steps.

The following demos are also available to check out and run locally with the Inngest Dev Server:

Further Reference