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:

However, when a failure triggers retries, a Durable Endpoint returns a redirect to a dedicated endpoint on Inngest Cloud to poll the final result.

Here is a snippet handling both the direct result and the redirected result after retries:

function handleError(error) {
  // ...
}

async function handleResult(result) {
  const result = await res.json()
  // ...
}

fetch(`/api/your-durable-endpoint`)
  .then((res) => {
    if (res.redirected) {
      // follow the redirect
      fetch(res.url)
        .then(handleResult)
        .catch(handleError);
    } else {
      handleResult(res)
    }
  })
  .catch(handleError);

As the Durable Endpoint redirects the request to a dedicated endpoint on Inngest's Cloud, fetch() cannot simply follow this redirect for you (CORS policy). Instead, you need to get the redirect URL (res.url) and trigger a new fetch() request.

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