Fetch: performing API requests or fetching data TypeScript only
The Inngest TypeScript SDK provides a step.fetch() API and a fetch() utility, enabling you to make requests to third-party APIs or fetch data in a durable way by offloading them to the Inngest Platform:
step.fetch()is a shorthand for making HTTP requests from within an Inngest function, and it also makes it easier to start parallel HTTP requests.- The
fetch()utility can be passed to packages that accept a customfetchimplementation, such asaxios.
![]()
Using step.fetch()
You can use step.fetch() to make HTTP requests within an Inngest function.
step.fetch() offloads the HTTP request to the Inngest Platform, so your service does not need to be active and waiting for the response.
src/inngest/functions.ts
import { inngest } from "./client"; export const retrieveTextFile = inngest.createFunction( { id: "retrieveTextFile" }, { event: "textFile/retrieve" }, async ({ step }) => { // The fetching of the text file is offloaded to the Inngest Platform const response = await step.fetch( "https://example-files.online-convert.com/document/txt/example.txt" ); // The Inngest function run is resumed when the HTTP request is complete await step.run("extract-text", async () => { const text = await response.text(); const exampleOccurences = text.match(/example/g); return exampleOccurences?.length; }); } ); step.fetch() is useful:
- In serverless environments, to offload long-running HTTP requests that might trigger timeouts.
- As a shorthand for making HTTP requests within an Inngest function, making it easier to start parallel HTTP requests using
Promise.all(). - As a best practice to ensure that all HTTP requests are durable and can be inspected in the Inngest Platform or Dev Server.
step.fetch() observability
All step.fetch() calls are visible in your Inngest Traces, allowing you to monitor and debug your HTTP requests:
![]()
Using the fetch() utility
A Fetch API-compatible function is exported, allowing you to make any HTTP requests durable if they're called within an Inngest function.
For example, a MyProductApi class that relies on axios can take a fetch parameter:
TypeScript
import { fetch } from "inngest"; const api = new MyProductApi({ fetch }); // A call outside an Inngest function will fall back to the global fetch await api.getProduct(1); // A call from inside an Inngest function will be made durable and offloaded to the Inngest Platform inngest.createFunction( { id: "my-fn" }, { event: "product/activated" }, async () => { await api.getProduct(1); }, ); ⚠️ fetch() and step.run()
Inngest's fetch() calls should not be performed inside of step.run() blocks. Doing so will result in fetch() to fallback to the global fetch implementation.
Why? The fetch() utility transforms the fetch calls into step.run() calls, which cannot be nested.
Within steps
By default, using Inngest's fetch retains all the functionality of requests made outside of an endpoint, but ensures that those made from inside are durable.
import { fetch as inngestFetch } from 'inngest'; import { generateText } from 'ai'; import { createAnthropic } from '@ai-sdk/anthropic'; // The AI SDK's createAnthropic objects can be passed a custom fetch implementation const anthropic = createAnthropic({ fetch: inngestFetch, }); // NOTE - Using this fetch outside of an Inngest function will fall back to the global fetch const response = await generateText({ model: anthropic('claude-3-5-sonnet-20240620'), prompt: 'Hello, world!', }); // A call from inside an Inngest function will be made durable inngest.createFunction( { id: "generate-summary" }, { event: "post.created" }, async ({ event }) => { // This will use step.fetch automatically! const response = await generateText({ model: anthropic('claude-3-5-sonnet-20240620'), prompt: `Summarize the following post: ${event.data.content}`, }); }, ); Using with AI SDK: Disable AI SDK retries
Important: When using Inngest's fetch with the AI SDK, disable the AI SDK's built-in retry mechanism and let Inngest handle retries instead.
The AI SDK has built-in retry logic that can interfere with Inngest's retry handling, especially when working with long-running models or serverless platforms with timeout limits (e.g., Vercel's 15-minute max timeout).
Why this matters:
- When AI SDK retries are enabled alongside Inngest's retry mechanism, the combined retry duration can exceed your platform's timeout limits
- For long-running models (like OpenAI's o3), this is especially problematic
- When a timeout occurs, the error messages can be confusing: Vercel cancels the request, but it appears in Inngest as an "Internal server error" (from Inngest, not Vercel), making debugging difficult
Recommended configuration:
import { generateText } from 'ai'; import { createOpenAI } from '@ai-sdk/openai'; import { fetch as inngestFetch } from 'inngest'; const openai = createOpenAI({ fetch: inngestFetch, }); inngest.createFunction( { id: "generate-with-o3" }, { event: "content/generate" }, async ({ event }) => { // Disable AI SDK retries - let Inngest handle them instead const response = await generateText({ model: openai('o3'), prompt: event.data.prompt, maxRetries: 0, // Critical: Set to 0 to let Inngest handle retries }); return response; }, ); By setting maxRetries: 0 in your AI SDK calls, you:
- Avoid timeout issues on serverless platforms
- Get clearer error messages when failures occur
- Leverage Inngest's retry mechanism, which is designed for long-running operations
- Benefit from Inngest's observability to see exactly what happened during each retry attempt
However, the same fetch is also exported as step.fetch, allowing you to create your APIs isolated within the function instead:
import { createAnthropic } from '@ai-sdk/anthropic'; import { fetch as inngestFetch } from 'inngest'; import { generateText } from 'ai'; const anthropic = createAnthropic({ fetch: inngestFetch, }); inngest.createFunction( { id: "generate-summary" }, { event: "post.created" }, async ({ step }) => { const response = await generateText({ model: anthropic('claude-3-5-sonnet-20240620'), prompt: `Summarize the following post: ${event.data.content}`, }); }, ); Fallbacks
By default, it will gracefully fall back to the global fetch if called outside of an Inngest function, though you can also set a custom fallback using the config method:
import { fetch } from "inngest"; const api = new MyProductApi({ fetch: fetch.config({ fallback: myCustomFetch }), }); You can also disable the fallback entirely:
import { fetch } from "inngest"; const api = new MyProductApi({ fetch: fetch.config({ fallback: undefined }), }); How it works
Inngest's fetch function uses some of the basic building blocks of Inngest to allow seamless creation of optionally durable code. When it's called, it will:
- Check the context in which it's running
- If not in an Inngest function, optionally use the fallback; otherwise,
- Report the request to Inngest
- Inngest makes the request
- Inngest continues the function with the
Responsereceived from your request
Critically, this means that your service does not have to be active for the duration of the call; we'll continue your function when we have a result, while also keeping it durable!