· 3 observations
Technical updates · 3
Package or technical metadata updated
View technical comparison →Package or technical metadata updated
View technical comparison →Package or technical metadata updated
View technical comparison →Inngest v0.4.3
Debug Inngest Cloud workflows.
From the developer
Not specified in the available declarations: limitations, pricing & account requirements.
Developer declarations; not independently tested. Listing last checked Nov 11, 2026. Package observed Nov 10, 2026.
From the marketplace listing
Connect your Inngest account to inspect deployed apps, functions, events, runs, traces, and Insights through OAuth MCP. Diagnose failures and carry out requested workflow operations in the selected environment. Coding hosts can also use the bundled skills to build durable functions and agents, audit codebases, and test locally with an optional Dev Server connection.
Language: English · Automatically detected from descriptions.
Exact text from the indicated source. A mention alone does not establish support for your task.
Connect your Inngest account to inspect deployed apps, functions, events, runs, traces, and Insights through OAuth MCP. Diagnose failures and carry out requested workflow operations in the selected environment. Coding hosts can also use the bundled skills to build durable functions and agents, audit codebases, and test locally with an optional Dev Server connection.
Code MCP
inngest durable-functions background-jobs agent-evals workflow codex mcp
· 3 observations
Package or technical metadata updated
View technical comparison →Package or technical metadata updated
View technical comparison →Package or technical metadata updated
View technical comparison →· 7 observations
Skill instructions changed from “Reference](../references/expressions.md)” to “Reference](../../references/expressions.md)”.
View comparison →Skill instructions changed from “Reference](../references/expressions.md)” to “Reference](../../references/expressions.md)”.
View comparison →Supporting files updated; open the comparison for details. Skill instructions changed from “Reference](../references/expressions.md)” to “Reference](../../references/expressions.md)”.
View comparison →Supporting file metadata differs
View technical comparison →Package or technical metadata updated
View technical comparison →Package or technical metadata updated
View technical comparison →· 1 observation
Package or technical metadata updated
View technical comparison →Find competitors to follow as you develop your plugin.
Twenty-three reusable Agent Skills for planning, implementation, review, verification, UI, and system work in ChatGPT and Codex.
Shared terms: debug, bundled, deploy, environment
Connect ChatGPT to Encore's cloud platform to inspect, understand, and troubleshoot Encore applications.
Shared terms: cloud, deploy, diagnose, environment
Aiven official plugin to provision and manage PostgreSQL, Kafka, and other data services on Aiven. Includes the Aiven MCP Server for proj...
Shared terms: cloud, deploy, server, mcp
InsForge skills for building AI-native apps with Postgres, auth, storage, compute, hosting, AI gateway, realtime, payments, integrations,...
Shared terms: cloud, coding, deploy, agent
Debug your event pipeline from your agent: errors, violations, failed loads. Official hosted MCP server for RudderStack.
Shared terms: debug, audit, event, failure
---
name: inngest-agent-evals
description: "Use when building, migrating, or debugging Agent Evals on Inngest: scoring AI agent or workflow outcomes, deferred scorers, sessions, traces, step experiments, experiment variant attribution, Insights queries, or production eval loops for prompts, models, tools, providers, and agent behavior. Covers TypeScript SDK v4 scoring beta APIs, `scoreMiddleware`, `step.score`, `inngest.score`, `createScorer`, `defer`, `group.experiment`, `experimentRef`, `meta.sessions`, and when to use durable workflow primitives for outcome-based evaluation."
---
# Inngest Agent Evals
Use this skill when the user wants to evaluate AI agents or AI workflows in
production, add scoring, compare prompts/models/tools, group related runs, or
debug why an agent outcome was good or bad.
Agent Evals is not a separate package. It is the production evaluation workflow
built from Inngest functions, durable steps, scores, deferred scorers, sessions,
traces, experiments, and Insights.
## Canonical References
Check the public docs first when exact API details matter:
- Agent Evals overview: https://www.inngest.com/docs/learn/agent-evals
- Scoring guide: https://www.inngest.com/docs/features/inngest-functions/steps-workflows/scoring
- Deferred scoring guide: https://www.inngest.com/docs/features/inngest-functions/steps-workflows/deferred-scoring
- Step experiments guide: https://www.inngest.com/docs/features/inngest-functions/steps-workflows/step-experiments
- Sessions: https://www.inngest.com/docs/features/events-triggers/sessions
- Traces: https://www.inngest.com/docs/platform/monitor/traces
- Insights: https://www.inngest.com/docs/platform/monitor/insights
- Scoring reference: https://www.inngest.com/docs/reference/typescript/v4/functions/scoring
- `group.experiment()` reference: https://www.inngest.com/docs/reference/typescript/v4/functions/group-experiment
- Launch context: https://www.inngest.com/blog/introducing-agent-evals
## Decision Flow
Start from the outcome, not the mechanism:
1. Identify the product or quality signal: helpful click, ticket resolution,
conversion, guardrail pass, retrieval quality, model confidence, latency,
cost, human review, or LLM-as-judge result.
2. Decide when the signal appears:
- During the run: use direct scoring with `step.score()` or
`inngest.score()`.
- After the run: use deferred scoring with `createScorer()` and `defer()`,
or explicit `inngest.score({ runId })`.
3. Decide how humans will inspect related work:
- Use `meta.sessions` for repeated high-cardinality identifiers such as
`conversation_id`, `ticket_id`, `agent_run_id`, or `import_id`.
- Use Insights for ad hoc historical analysis, low-cardinality filters, SQL
aggregates, and broad investigation.
4. Decide whether to compare variants:
- Use `group.experiment()` for prompt, model, provider, tool, workflow, or
rollout comparisons.
- Pass `experimentRef` to deferred or later scores when the score should be
credited to the selected variant.
5. Preserve traceability:
- Keep model calls, tool calls, waits, database writes, and scoring work in
durable steps so traces explain why the score happened.
## Setup Requirements
- Use TypeScript SDK v4 and install the latest SDK: `npm install inngest@latest`.
- Scoring and deferred scoring are beta APIs; verify current imports against
the docs before shipping user-facing examples.
- `step.score()` requires `scoreMiddleware()` from `inngest/experimental` on
the Inngest client.
- `createScorer()` is imported from `inngest/experimental` and the scorer must
be registered in the serve handler with other functions.
- Sessions sent through the TypeScript SDK require v4.7.0 or later.
- Step experiments require v4.8.0 or later for `group.experiment()` and the
`experiment` helper from `inngest`.
Client shape:
```typescript
import { Inngest } from "inngest";
import { scoreMiddleware } from "inngest/experimental";
expPreview of the first 4,000 characters. Read full instructions →
---
name: inngest-agents
description: Use when building durable AI agents or agentic workflows with Inngest and AgentKit, including model calls, tool calls, multi-agent networks, human approval, realtime progress, provider rate limits, crash-safe execution, and Agent Evals handoff. Covers AgentKit, `step.ai`, `step.run`, `step.waitForEvent`, native realtime, and when to use lower-level Inngest primitives instead of an in-memory agent loop. Use `inngest-agent-evals` with this skill when the user wants scoring, sessions, experiments, deferred scorers, or outcome-based evaluation for the agent.
---
# Inngest Agents
Use this skill when the user wants to build, migrate, or debug an AI agent,
multi-step AI workflow, tool-calling loop, support agent, research agent,
human-in-the-loop review flow, or realtime agent UI.
Inngest's AgentKit defines agents with `createAgent`; when an AgentKit run is
owned by an Inngest function, model calls use Inngest `step.ai` so they retry
and cache model results durably. Use the lower-level Inngest step primitives
around the agent for database reads/writes, tool side effects, waits,
approvals, realtime progress, and flow control.
Official references:
- AgentKit agents: https://agentkit.inngest.com/concepts/agents
- `createAgent`: https://agentkit.inngest.com/reference/create-agent
- AI inference and `step.ai`: https://www.inngest.com/docs/features/inngest-functions/steps-workflows/step-ai-orchestration
- Agent Evals: https://www.inngest.com/docs/learn/agent-evals
- AgentKit realtime hooks: https://www.inngest.com/changelog/2025-09-24-agentkit-use-agent
## Copyable Example
When starting a durable support or tool-calling agent from scratch, inspect the
companion example at `../../examples/durable-agent`. It shows the expected
agent-first shape: quick HTTP trigger, typed events, AgentKit inside an
Inngest function, step-scoped context loading, human approval with
`step.waitForEvent`, and durable side effects after approval.
## When to Use Inngest for Agents
Good fit:
- Agent can take longer than one HTTP request.
- Agent calls tools, APIs, databases, browsers, sandboxes, or MCP servers.
- Agent needs to survive deploys, crashes, serverless timeouts, or model/API
failures.
- Agent may wait for human approval, external callbacks, scheduled follow-up,
or user input.
- Agent progress should stream to a UI from the durable workflow.
- Model/provider calls need concurrency or throttle limits.
- Duplicate sends, charges, writes, or model calls would be costly.
Not usually worth it:
- One short, read-only model call with no side effects and no need for durable
progress.
- UI-only autocomplete where losing the request is acceptable.
## Architecture
Use this shape unless the repo already has a stronger established pattern:
1. The HTTP/server action layer validates auth, stores the user's intent if
needed, emits an event with a stable `id`, and returns quickly.
2. An Inngest function owns the agent run.
3. Load state and external context inside `step.run`.
4. Create AgentKit agents inside the function or import agent/network
factories.
5. Run model inference through AgentKit / `step.ai`; wrap non-model tool side
effects in `step.run`.
6. Use `step.waitForEvent` or `step.waitForSignal` for human approval and
external callbacks.
7. Publish durable progress with native realtime.
8. Add sessions and scores when the agent outcome needs to be evaluated later.
9. Apply flow control at the function level for provider and tenant limits.
## Basic AgentKit Function
Prefer a small, typed function first; add networks and extra tools after the
single-agent path is proven.
```typescript
import { createAgent, openai } from "@inngest/agent-kit";
import { inngest } from "@/inngest/client";
export const summarizeTicket = inngest.createFunction(
{
id: "summarize-ticket",
triggers: [{ event: "support/ticket.created" }],
concurrency: [{ key: "event.data.accountId", limit: 2 }]
},
asPreview of the first 4,000 characters. Read full instructions →
--- name: inngest-api description: >- Use when the user explicitly asks for the Inngest REST API v2, raw HTTP, OpenAPI, API docs, API authentication, or an endpoint that the Inngest CLI does not expose. Covers api-docs.inngest.com, llms.txt, the OpenAPI v2 spec, Bearer authentication with API keys or signing keys, production and local base URLs, raw curl/fetch requests, request-shape discovery, pagination, secret redaction, and when to prefer the `inngest-api-cli` skill instead. --- # Inngest REST API v2 For Cloud operations with connected MCP tools, use `inngest-cloud` first. Keep this skill for explicit terminal/HTTP work or a capability missing from MCP. Do not ask for an API key when OAuth MCP can complete the task. Use this skill for raw REST API v2 work and API reference lookup. If the task can be completed through `npx inngest-cli@latest api`, use `inngest-api-cli` instead; the CLI is safer for agents because it handles target/auth flags and endpoint command wiring. ## Prefer CLI First Use `inngest-api-cli` for: - Run and trace debugging from a run ID or event ID. - Account, environment, key, webhook, app sync, and function invocation checks. - Insights table/schema/query workflows. - Local dev server or Cloud operational checks. Use raw REST API v2 only when: - The CLI does not expose the needed endpoint. - The user explicitly asks for HTTP, curl, fetch, OpenAPI, or API docs. - You need to inspect request/response schemas before deciding what to do. ## Docs Lookup When precision matters, fetch current docs instead of guessing: - API overview: `https://api-docs.inngest.com/` - Authentication: `https://api-docs.inngest.com/authentication` - LLM index: `https://api-docs.inngest.com/llms.txt` - OpenAPI v2 spec: `https://api-docs.inngest.com/api-specs/v2.json` - Markdown page pattern: add `.md` to a docs URL, for example `https://api-docs.inngest.com/v2/runs/GetFunctionTrace.md` - Endpoint request/response schemas: [references/rest-api-v2.md](references/rest-api-v2.md) If a Markdown page returns an error or omits generated reference details, use the OpenAPI spec for methods, paths, parameters, request bodies, and schemas. ## Base URLs - Cloud v2: `https://api.inngest.com/v2` - Local dev server v2: `http://localhost:8288/api/v2` - API docs say the dev server may also be reached through the local server origin. Confirm the actual dev server port before making local requests. ## Authentication The REST API uses Bearer token authentication. - Prefer `INNGEST_API_KEY` for requests from CI, scripts, tools, and agents. - Signing keys are primarily for apps communicating with Inngest; use them for API requests only when that is the available, appropriate credential. - API keys are for v2 endpoints only. - Include `X-Inngest-Env` or use an environment-scoped API key when operating outside the default production environment. - Never paste, print, commit, or log API keys, event keys, signing keys, webhook URLs, or decrypted secrets. Example: ```bash curl -fsSL \ -H "Authorization: Bearer $INNGEST_API_KEY" \ -H "X-Inngest-Env: $INNGEST_ENV" \ https://api.inngest.com/v2/account ``` ## Endpoint Discovery Use the OpenAPI spec as the source of truth: ```bash curl -fsSL https://api-docs.inngest.com/api-specs/v2.json ``` Current v2 areas include account, environments, keys, webhooks, apps, function invocation, event-run lookup, function runs, traces, Insights, and partner APIs. Endpoint coverage can change, so inspect the spec before writing a raw request. For API-only or access-gated endpoints, such as partner-account endpoints, confirm the user has the needed access before attempting a call. ## Request Rules - Derive method, path, query params, headers, and body from OpenAPI. - Do not invent undocumented request fields. - Use structured JSON parsing before making decisions from responses. - Use body files or here-docs for complex JSON instead of shell-escaped one liners. - Add pagin
Preview of the first 4,000 characters. Read full instructions →
Referenced files: 1 — file references are metadata, not package contents.
--- name: inngest-api-cli description: >- Use when operating Inngest API resources from the terminal with `npx inngest-cli@latest api`: Cloud/local run debugging, event-run lookup, function traces, function invocation, app syncs, webhooks, environments, keys, account checks, and Insights queries. Provides prescriptive command routing for agents: which CLI command to run for a run ID, event ID, app ID, function ID, Cloud environment, API key, missing ID, or potentially mutating operation. Use `inngest-cli` for dev server setup/general CLI workflows and `inngest-api` only when raw REST API v2 docs or OpenAPI fallback are needed. --- # Inngest API CLI For Cloud operations with connected MCP tools, use `inngest-cloud` first. Keep this skill for explicit terminal/HTTP work or a capability missing from MCP. Do not ask for an API key when OAuth MCP can complete the task. Use this skill when the task is operational: inspect, debug, sync, invoke, or query Inngest API resources through the terminal. This skill is intentionally prescriptive so agents can act without guessing. For general CLI setup, `inngest dev`, Docker, local testing, MCP setup, or self-hosted `inngest start`, use `inngest-cli`. For code changes, pair this with the domain skill that owns the code pattern: `inngest-setup`, `inngest-durable-functions`, `inngest-events`, `inngest-steps`, `inngest-flow-control`, `inngest-realtime`, or `inngest-middleware`. ## First Move Verify the current CLI surface before relying on memory: ```bash npx inngest-cli@latest api --help npx inngest-cli@latest api <command> --help ``` The active API command is `inngest api`. If prompt context or old docs mention `inngest alpha api`, switch to `inngest api`. Use `inngest-api` only when: - The CLI does not expose the needed endpoint. - The user explicitly asks for raw REST API v2. - You need the OpenAPI spec or LLM API docs to resolve request shape. For complete command flags, read [references/cli-commands.md](references/cli-commands.md) after this skill triggers. ## Target Rules - Local is the default target for `inngest api`. - Cloud Production requires `--prod`. - Non-production Cloud environments require `INNGEST_ENV=<name>` or `--env`. - Prefer `INNGEST_API_KEY` for Cloud API access. - Do not pass API keys inline with `--api-key <secret>` unless the user explicitly accepts process-list and transcript exposure. - Never write API keys, event keys, signing keys, webhook URLs, or decrypted secrets into source files, docs, fixtures, or final answers. Common targets: ```bash npx inngest-cli@latest api health npx inngest-cli@latest api --prod get-account INNGEST_ENV=staging npx inngest-cli@latest api --prod get-webhooks npx inngest-cli@latest api --api-host http://127.0.0.1 --api-port 8288 health ``` ## Local Development For local app work: 1. Start the user's app with local dev mode when applicable, for example `INNGEST_DEV=1 npm run dev`. 2. Start the dev server: ```bash npx inngest-cli@latest dev ``` 3. Prefer Dev Server MCP tools, when available, to list local functions, send test events, inspect runs, and watch status. 4. Use `npx inngest-cli@latest api ...` for API-compatible local checks, command-help verification, and workflows not exposed through MCP. If the local API says the dev server is unavailable, start `inngest dev` or switch to Cloud with `--prod` when the user is debugging deployed runs. ## Command Routing Use this table before asking the human for more context. | Situation | Command path | | --- | --- | | Check CLI/API reachability | `api health` | | Confirm Cloud auth | `api --prod get-account` | | List environments | `api --prod get-account-envs --limit 10` | | List event keys | `api --prod get-account-event-keys --limit 10` | | List signing keys | `api --prod get-account-signing-keys --limit 10` | | List webhooks | `api --prod get-webhooks` | | User gives a run ID | `api --prod get-function-run <run_id>` | | Need st
Preview of the first 4,000 characters. Read full instructions →
Referenced files: 1 — file references are metadata, not package contents.
---
name: inngest-brownfield-audit
description: Use when analyzing an existing TypeScript or JavaScript codebase to decide where and how to introduce Inngest. Covers repository discovery, framework and package detection, finding durability gaps in HTTP handlers, webhooks, cron jobs, queues, long-running jobs, AI agents, Agent Evals, polling loops, eval loops, and side-effect-heavy code, then producing and implementing an incremental integration plan.
---
# Inngest Brownfield Audit
Use this skill when the user asks Codex to inspect an existing codebase, add
Inngest "where it makes sense", migrate fragile background work, or find
durability gaps before making changes.
This is an agent-first workflow. Do the audit from evidence in the repo, name
the specific files and call sites that drove each conclusion, and make small
integration moves that preserve current behavior.
## When to Trigger
Use this skill for requests like:
- "Audit this repo for Inngest opportunities"
- "Add Inngest to this codebase"
- "Make our webhooks / cron jobs / background tasks reliable"
- "Find places where work can be lost on deploy or process crash"
- "Replace fragile polling, delayed jobs, or fire-and-forget promises"
- "Make this AI workflow / agent durable"
If the user is starting from scratch instead of a brownfield repo, use
`inngest-setup`, `inngest-durable-functions`, `inngest-events`,
`inngest-steps`, and, for AI workflows, the agent patterns in this skill. Use
`inngest-agent-evals` when the request includes scoring, sessions, experiments,
deferred scorers, Insights, or outcome-based evaluation.
## Audit Loop
1. **Map the project shape.**
- Read `package.json`, workspace files, app/router structure, server entry
points, deployment config, and test scripts.
- Identify framework: Next.js App Router, Next.js Pages Router, Express,
Hono, Fastify, Remix, SvelteKit, Astro, NestJS, worker-only service, or
other.
- Detect package manager and TypeScript conventions before adding files.
2. **Find existing Inngest usage.**
- Search for `inngest`, `createFunction`, `serve(`, `/api/inngest`,
`INNGEST_`, `step.run`, `step.sleep`, `step.waitForEvent`,
`step.sendEvent`, `step.invoke`, `step.ai`, `inngest.send`, and
`@inngest/realtime`.
- If Inngest exists, inspect version, client config, serve endpoint,
registered functions, event naming, env vars, and v3/v4 API shape before
changing anything.
3. **Find durability gaps.**
- Search for fire-and-forget work: `void someAsync()`, un-awaited promises,
`.then(` chains, `setTimeout`, `setInterval`, detached jobs after HTTP
response, and background work in route handlers.
- Search for cron and schedulers: `cron`, `node-cron`, `agenda`, `bull`,
`bullmq`, `bee-queue`, `qstash`, `sqs`, `temporal`, `trigger.dev`,
deployment cron config, and scheduled API routes.
- Search for webhooks and at-least-once producers: Stripe, Clerk, GitHub,
Slack, Shopify, HubSpot, Linear, Svix, and generic `webhook`.
- Search for long-running work: PDF generation, exports, video/image
processing, embeddings, bulk email, imports, ETL, sync jobs, polling loops,
retries, and external API calls.
- Search for AI agent shapes: tool loops, LLM calls, streaming tokens,
human approval, multi-step reasoning, vector search, eval loops, scoring,
experiment assignment, user-feedback signals, and provider calls that need
rate limits or retry-safe state.
4. **Classify each candidate.**
- **P0:** user-visible loss, duplicate charge/email/action, timeout, missed
webhook, or crash-prone workflow.
- **P1:** fragile but recoverable background work, manual retry burden,
noisy 429s, or poor observability.
- **P2:** cleanup, ergonomics, or future migration opportunity.
- For each candidate, record: file, current trigger, side effects,
idempotency key, failure mode, recommended Inngest primitive, migration
sPreview of the first 4,000 characters. Read full instructions →
---
name: inngest-cli
description: Use when installing or running the Inngest CLI and Dev Server for local development, local testing, serve endpoint debugging, Docker or Docker Compose setup, MCP configuration, self-hosted `inngest start`, or deployment workflow checks. Covers `inngest dev`, `inngest start`, auto-discovery, config files, environment variables, `@inngest/test`, local event sending, platform gotchas, and production/self-hosted server flags.
---
# Inngest CLI
Master the Inngest CLI for local development, testing, and self-hosted production. The CLI provides the Dev Server — a fully-featured, open-source local version of the Inngest Platform.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
Use this skill for CLI setup, Dev Server workflows, local testing, Docker, MCP, and self-hosted server operations. For run/trace inspection through `inngest api`, use `inngest-api-cli` when available.
## Installation
```bash
# npx (recommended — always latest)
npx inngest-cli@latest dev
# yarn
yarn dlx inngest-cli@latest dev
# pnpm
pnpm dlx inngest-cli@latest dev
# Global install
npm install -g inngest-cli
# Docker
docker pull inngest/inngest
```
If your npm configuration disables lifecycle scripts and the binary is missing, retry with `npx --ignore-scripts=false inngest-cli@latest dev`. Bun does not support lifecycle scripts by default, so prefer `npx` for the CLI even in Bun projects.
## `inngest dev` — Local Dev Server
Starts an in-memory local version of Inngest with a browser UI at `http://localhost:8288`.
```bash
# Auto-discover apps on common ports/endpoints
npx inngest-cli@latest dev
# Specify your app URL
npx inngest-cli@latest dev -u http://localhost:3000/api/inngest
# Custom port
npx inngest-cli@latest dev -p 9999
# Multiple apps
npx inngest-cli@latest dev \
-u http://localhost:3000/api/inngest \
-u http://localhost:4000/api/inngest
# Disable auto-discovery (use with -u)
npx inngest-cli@latest dev --no-discovery -u http://localhost:3000/api/inngest
```
### CLI Flags
| Flag | Short | Default | Description |
|---|---|---|---|
| `--sdk-url` | `-u` | `http://localhost:3000/api/inngest` | App serve endpoint URL(s) |
| `--port` | `-p` | `8288` | Dev Server port |
| `--host` | | | Dev Server host |
| `--no-discovery` | | `false` | Disable auto-discovery of apps |
| `--no-poll` | | `false` | Disable polling apps for changes |
| `--config` | | | Path to configuration file |
| `--connect-gateway-port` | | `8289` | Connect gateway endpoint port |
| `--persist` | | `false` | Persist data between restarts |
| `--poll-interval` | | `5` | Seconds between app polling checks |
| `--queue-workers` | | `100` | Number of executor workers |
| `--retry-interval` | | `0` | Linear retry interval in seconds |
| `--tick` | | `150` | Executor queue polling interval in milliseconds |
### Auto-Discovery
Without `--no-discovery`, the Dev Server scans common ports and endpoints automatically:
**Ports scanned:** Common development ports including 3000, 3030, and others
**Endpoints scanned:**
- `/api/inngest`
- `/x/inngest`
- `/.netlify/functions/inngest`
- `/.redwood/functions/inngest`
## Configuration File
Create an `inngest.json` (or `.yaml`, `.toml`) in your project root. The CLI walks up directories to find it.
```json
{
"sdk-url": [
"http://localhost:3000/api/inngest",
"http://localhost:3030/api/inngest"
],
"no-discovery": true
}
```
```yaml
# inngest.yaml
sdk-url:
- "http://localhost:3000/api/inngest"
- "http://localhost:3030/api/inngest"
no-discovery: true
```
## Environment Variables
| Variable | Description |
|---|---|
| `INNGEST_DEV` | `=1` enables Dev Mode (disables signature verification). `=0` forces Cloud mode. Accepts a URL (e.g., `http://localhost:8288`). **Defaults to Cloud mode if unset.** |
| `INNGEST_BASE_URL` | Host foPreview of the first 4,000 characters. Read full instructions →
Referenced files: 1 — file references are metadata, not package contents.
--- name: inngest-cloud description: Inspect and operate Inngest Cloud through its OAuth MCP connection. Use for deployed apps and functions, failed or slow runs, traces, events, environments, sessions, experiments, and Insights. Prefer this for Cloud operations when MCP tools are available; use CLI or REST skills for explicit terminal or HTTP tasks. --- # Inngest Cloud Use the connected Inngest Cloud MCP server at `https://api.inngest.com/mcp`. Read the tools and input schemas exposed by the current connection before constructing calls. Tool names below omit host-specific prefixes. ## Connection and target - Use the host's OAuth sign-in or reconnect flow. Do not request tokens or API keys in chat. A plugin connection does not authenticate a separate CLI. - Resolve the account with `fetch_account` when account context is missing. Use `list_envs` and the user's task to resolve the environment. Carry the selected `env` through environment-specific calls; do not infer production from an omitted value or switch environments after an access error. - Use `get_apps` and `list_functions` to discover identifiers. Don't ask the user for an ID the tools can find. Ask when multiple accounts, environments, apps, or functions fit the request. - A `401` needs reconnection; a scope or permission error needs the appropriate grant. Neither means that a resource is absent. Do not fall back to another credential to bypass the connection's access limits. - The local Dev Server is a separate, opt-in connection named `inngest-dev`. Reuse an existing local connection under its configured name. Both servers can coexist. Use the server matching the requested target and never fall back from local to Cloud on a connection failure. For local setup, use `inngest-cli` when installed. Cloud MCP cannot see a local process. ## Investigate a run 1. If the user gives a run ID, use `get_run`. Otherwise find a bounded set with `list_runs` or `list_function_runs`, using the requested time range, status, app, and function. Follow pagination when needed and report the query window. 2. Use `get_run_trace` for the relevant run. Start with trace metadata and fetch input/output only when needed to explain a failure. Inspect nested spans. 3. Separate observed failures, waits, retries, and cancellations from hypotheses. Cite the run ID, failed step, and error that support the conclusion. An empty result is evidence only about the filters and accessible environment queried. 4. When code is available, connect the failed step to its implementation and propose or make the requested fix. In chat without repository access, give the diagnosis and concrete code guidance without claiming a patch was applied. **Do:** inspect a failed run and trace before deciding whether a retry helps. **Don't:** rerun, cancel, invoke, or send an event merely to diagnose a failure. ## Events and operations For an explicitly requested event test, resolve the environment and inspect the function's trigger first. Send the requested event with `send_event`, then use `get_event_runs` and inspect the resulting runs. Sending an event or invoking a function can execute real application side effects. Before a write, resolve the exact target, payload, and requested effect. Honor existing user authorization; ask only when the scope or target is unclear. Use mutations such as `rerun`, `cancel_run`, `invoke_function`, `sync_app`, and environment or webhook changes only when they are part of the user's request. Do not retry a timed-out write blindly: check for its result first to avoid sending duplicate events or starting duplicate runs. ## Insights, sessions, and experiments Use `list_insights_tables` and the live schema before building an Insights query. Bound time ranges and result counts, prefer aggregates, and inspect SQL returned by `query_insights_prompt` before executing it with `query_insights`. Use the session and experiment tools for their respec
Preview of the first 4,000 characters. Read full instructions →
---
name: inngest-durable-functions
description: Use when building functions that must survive process crashes, retry automatically on failure, run on a schedule, react to events, or maintain state across infrastructure failures — e.g., webhook handlers that drop events, flaky cron jobs, background jobs that fail mid-execution, or workflows that need to resume where they left off. Covers Inngest function configuration, triggers (events, cron, invoke), step execution and memoization, idempotency, cancellation, error handling, retries, logging, and observability.
---
# Inngest Durable Functions
Master Inngest's durable execution model for building fault-tolerant, long-running workflows. This skill covers the complete lifecycle from triggers to error handling.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
## Core Concepts You Need to Know
### **Durable Execution Model**
- **Each step** should encapsulate side-effects and non-deterministic code
- **Memoization** prevents re-execution of completed steps
- **State persistence** survives infrastructure failures
- **Automatic retries** with configurable retry count
### **Step Execution Flow**
```typescript
// ❌ BAD: Non-deterministic logic outside steps
async ({ event, step }) => {
const timestamp = Date.now(); // This runs multiple times!
const result = await step.run("process-data", () => {
return processData(event.data);
});
};
// ✅ GOOD: All non-deterministic logic in steps
async ({ event, step }) => {
const result = await step.run("process-with-timestamp", () => {
const timestamp = Date.now(); // Only runs once
return processData(event.data, timestamp);
});
};
```
## Function Limits
**Every Inngest function has these hard limits:**
- **Maximum 1,000 steps** per function run
- **Maximum 4MB** returned data for each step
- **Maximum 32MB** combined function run state including, event data, step output, and function output
- Each step = separate HTTP request (~50-100ms overhead)
If you're hitting these limits, break your function into smaller functions connected via `step.invoke()` or `step.sendEvent()`.
## When to Use Steps
**Always wrap in `step.run()`:**
- API calls and network requests
- Database reads and writes
- File I/O operations
- Any non-deterministic operation
- Anything you want retried independently on failure
**Never wrap in `step.run()`:**
- Pure calculations and data transformations
- Simple validation logic
- Deterministic operations with no side effects
- Logging (use outside steps)
## Function Creation
### Basic Function Structure
```typescript
const processOrder = inngest.createFunction(
{
id: "process-order", // Unique, never change this
triggers: [{ event: "order/created" }],
retries: 4, // Default: 4 retries per step
concurrency: 10 // Max concurrent executions
},
async ({ event, step }) => {
// Your durable workflow
}
);
```
### **Step IDs and Memoization**
```typescript
// Step IDs can be reused - Inngest handles counters automatically
const data = await step.run("fetch-data", () => fetchUserData());
const more = await step.run("fetch-data", () => fetchOrderData()); // Different execution
// Use descriptive IDs for clarity
await step.run("validate-payment", () => validatePayment(event.data.paymentId));
await step.run("charge-customer", () => chargeCustomer(event.data));
await step.run("send-confirmation", () => sendEmail(event.data.email));
```
## Triggers and Events
### **Event Triggers**
Triggers are defined in the `triggers` array in the first argument of `createFunction`:
```typescript
// Single event trigger
inngest.createFunction(
{ id: "my-fn", triggers: [{ event: "user/signup" }] },
async ({ event }) => { /* ... */ }
);
// Event with conditional filter
inngest.createFunction(
{ id: "my-fn", triggers: [{ ePreview of the first 4,000 characters. Read full instructions →
Referenced files: 4 — file references are metadata, not package contents.
---
name: inngest-events
description: Use when designing event-driven workflows, decoupling services, implementing fan-out patterns (one trigger, many downstream handlers), implementing idempotent event handling with IDs (24-hour dedupe window), or handling at-least-once delivery from external sources like Stripe webhooks. Covers Inngest event schema, payload format, naming conventions, IDs for idempotency, the ts param, fan-out patterns, and system events like inngest/function.failed.
---
# Inngest Events
Master Inngest event design and delivery patterns. Events are the foundation of Inngest - learn to design robust event schemas, implement idempotency, leverage fan-out patterns, and handle system events effectively.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
## Event Payload Format
Every Inngest event is a JSON object with required and optional properties:
### Required Properties
```typescript
type Event = {
name: string; // Event type (triggers functions)
data: object; // Payload data (any nested JSON)
};
```
### Complete Schema
```typescript
type EventPayload = {
name: string; // Required: event type
data: Record<string, any>; // Required: event data
id?: string; // Optional: deduplication ID
ts?: number; // Optional: timestamp (Unix ms)
v?: string; // Optional: schema version
};
```
### Basic Event Example
```typescript
await inngest.send({
name: "billing/invoice.paid",
data: {
customerId: "cus_NffrFeUfNV2Hib",
invoiceId: "in_1J5g2n2eZvKYlo2C0Z1Z2Z3Z",
userId: "user_03028hf09j2d02",
amount: 1000,
metadata: {
accountId: "acct_1J5g2n2eZvKYlo2C0Z1Z2Z3Z",
accountName: "Acme.ai"
}
}
});
```
## Event Naming Conventions
**Use the Object-Action pattern:** `domain/noun.verb`
### Recommended Patterns
```typescript
// ✅ Good: Clear object-action pattern
"billing/invoice.paid";
"user/profile.updated";
"order/item.shipped";
"ai/summary.completed";
// ✅ Good: Domain prefixes for organization
"stripe/customer.created";
"intercom/conversation.assigned";
"slack/message.posted";
// ❌ Avoid: Unclear or inconsistent
"payment"; // What happened?
"user_update"; // Use dots, not underscores
"invoiceWasPaid"; // Too verbose
```
### Naming Guidelines
- **Past tense:** Events describe what happened (`created`, `updated`, `failed`)
- **Dot notation:** Use dots for hierarchy (`billing/invoice.paid`)
- **Prefixes:** Group related events (`api/user.created`, `webhook/stripe.received`)
- **Consistency:** Establish patterns and stick to them
## Event IDs and Idempotency
**When to use IDs:** Prevent duplicate processing when events might be sent multiple times.
### Basic Deduplication
```typescript
await inngest.send({
id: "cart-checkout-completed-ed12c8bde", // Unique per event type
name: "storefront/cart.checkout.completed",
data: {
cartId: "ed12c8bde",
items: ["item1", "item2"]
}
});
```
### ID Best Practices
```typescript
// ✅ Good: Specific to event type and instance
id: `invoice-paid-${invoiceId}`;
id: `user-signup-${userId}-${timestamp}`;
id: `order-shipped-${orderId}-${trackingNumber}`;
// ❌ Bad: Generic IDs shared across event types
id: invoiceId; // Could conflict with other events
id: "user-action"; // Too generic
id: customerId; // Same customer, different events
```
**Deduplication window:** 24 hours from first event reception
See **inngest-durable-functions** for idempotency configuration.
## The `ts` Parameter for Delayed Delivery
**When to use:** Schedule events for future processing or maintain event ordering.
### Future Scheduling
```typescript
const oneHourFromNow = Date.now() + 60 * 60 * 1000;
await inngest.send({
name: "trial/reminder.send",
ts: oneHourFromNow, // Deliver in 1 hour
data: {
userId: "user_123",
trialExpiresAt: "2024-02-15T12:00:00Z"
}
})Preview of the first 4,000 characters. Read full instructions →
---
name: inngest-flow-control
description: "Use when handling external API rate limits (e.g., OpenAI 429s, HubSpot or Stripe rate limits), preventing duplicate work from rapid event bursts (debouncing user actions), spreading load over time, ensuring per-tenant fairness, processing events in batches, limiting concurrent runs of the same operation, or assigning priority to important runs. Covers Inngest flow control: concurrency limits with keys, throttling, rate limiting, debounce, priority, singleton, and event batching."
---
# Inngest Flow Control
Master Inngest flow control mechanisms to manage resources, prevent overloading systems, and ensure application reliability. This skill covers all flow control options with prescriptive guidance on when and how to use each.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
## Quick Decision Guide
- **"Limit how many run at once"** → Concurrency
- **"Spread runs over time"** → Throttling
- **"Block after N runs in a period"** → Rate Limiting
- **"Wait for activity to stop, then run once"** → Debounce
- **"Only one run at a time for this key"** → Singleton
- **"Process events in groups"** → Batching
- **"Some runs are more important"** → Priority
## Concurrency
**When to use:** Limit the number of executing steps (not function runs) to manage computing resources and prevent system overwhelm.
**Key insight:** Concurrency limits active code execution, not function runs. A function waiting on `step.sleep()` or `step.waitForEvent()` doesn't count against the limit.
### Basic Concurrency
```typescript
inngest.createFunction(
{
id: "process-images",
concurrency: 5,
triggers: [{ event: "media/image.uploaded" }]
},
async ({ event, step }) => {
// Only 5 steps can execute simultaneously
await step.run("resize", () => resizeImage(event.data.imageUrl));
}
);
```
### Concurrency with Keys (Multi-tenant)
Use `key` parameter to apply limit per unique value of the key.
```typescript
inngest.createFunction(
{
id: "user-sync",
concurrency: [
{
key: "event.data.user_id",
limit: 1
}
],
triggers: [{ event: "user/profile.updated" }]
},
async ({ event, step }) => {
// Only 1 step per user can execute at once
// Prevents race conditions in user-specific operations
}
);
```
### Account-level Shared Limits
```typescript
inngest.createFunction(
{
id: "ai-summary",
concurrency: [
{
scope: "account",
key: `"openai"`,
limit: 60
}
],
triggers: [{ event: "ai/summary.requested" }]
},
async ({ event, step }) => {
// Share 60 concurrent OpenAI calls across all functions
}
);
```
**When to use each:**
- Basic: Protect databases or limit general capacity
- Keyed: Multi-tenant fairness, prevent "noisy neighbor" issues
- Account-level: Share quotas across multiple functions (API limits)
## Throttling
**When to use:** Control the rate of function starts over time to work around API rate limits or smooth traffic spikes.
**Key difference from concurrency:** Throttling limits function run starts; concurrency limits step execution.
```typescript
inngest.createFunction(
{
id: "sync-crm-data",
throttle: {
limit: 10, // 10 function starts
period: "60s", // per minute
burst: 5, // plus 5 immediate bursts
key: "event.data.customer_id" // per customer
},
triggers: [{ event: "crm/contact.updated" }]
},
async ({ event, step }) => {
// Respects CRM API rate limits: 10 calls/min per customer
await step.run("sync", () => crmApi.updateContact(event.data));
}
);
```
**Configuration:**
- `limit`: Functions that can start per period
- `period`: Time window (1s to 7d)
- `burst`: Extra immediate starts allowed
- `key`: Apply limits per unique key value
## RaPreview of the first 4,000 characters. Read full instructions →
---
name: inngest-middleware
description: Use when adding cross-cutting concerns to durable functions — structured logging or tracing across all functions, error tracking with Sentry, payload encryption for sensitive data, dependency injection of clients (DB, Stripe, etc.) into function handlers, custom telemetry, or behavior that should apply uniformly across many functions. Covers Inngest middleware lifecycle, creating custom middleware, dependencyInjectionMiddleware, @inngest/middleware-encryption, @inngest/middleware-sentry, and custom middleware patterns.
---
# Inngest Middleware
Master Inngest middleware to handle cross-cutting concerns like logging, error tracking, dependency injection, and data transformation. Middleware runs at key points in the function lifecycle, enabling powerful patterns for observability and shared functionality.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
> **Note:** The middleware system was significantly rewritten in v4. The lifecycle hooks documented here reflect the v4 API. If migrating from v3, consult the [migration guide](https://www.inngest.com/docs-markdown/reference/typescript/v4/migrations/v3-to-v4) for details on breaking changes.
> **⚠ For Realtime use the `inngest-realtime` skill, NOT this one.** Inngest v3 used `realtimeMiddleware()` from `@inngest/realtime` to inject a `publish` arg into function handlers. **v4 ships realtime natively** — `step.realtime.publish` is built-in, no middleware required. Do NOT install `@inngest/realtime` on a v4 project (it's a v3-era package and produces `TypeError: Cls is not a constructor` at runtime). See the `inngest-realtime` skill for the v4 pattern.
## What is Middleware?
Middleware allows code to run at various points in an Inngest client's lifecycle - during function execution, event sending, and more. Think of middleware as hooks into the Inngest execution pipeline.
**When to use middleware:**
- **Observability:** Add logging, tracing, or metrics
- **Dependency injection:** Share client instances across functions
- **Data transformation:** Encrypt/decrypt, validate, or enrich data
- **Error handling:** Custom error tracking and alerting
- **Authentication:** Validate user context or permissions
## Middleware Lifecycle
Middleware can be registered at **client-level** (affects all functions) or **function-level** (affects specific functions).
### Execution Order
```typescript
const inngest = new Inngest({
id: "my-app",
middleware: [
loggingMiddleware, // Runs 1st
errorMiddleware // Runs 2nd
]
});
inngest.createFunction(
{
id: "example",
middleware: [
authMiddleware, // Runs 3rd
metricsMiddleware // Runs 4th
],
triggers: [{ event: "test" }]
},
async () => {
/* function code */
}
);
```
**Order matters:** Client middleware runs first, then function middleware, in the order specified.
## Creating Custom Middleware
### Basic Middleware Structure
```typescript
import { InngestMiddleware } from "inngest";
const loggingMiddleware = new InngestMiddleware({
name: "Logging Middleware",
init() {
// Setup phase - runs when client initializes
const logger = setupLogger();
return {
// Function execution lifecycle
// Note: `fn` is loosely typed in middleware generics; fn.id works at runtime
onFunctionRun({ ctx, fn }) {
return {
beforeExecution() {
logger.info("Function starting", {
functionId: fn.id,
eventName: ctx.event.name,
runId: ctx.runId
});
},
afterExecution() {
logger.info("Function completed", {
functionId: fn.id,
runId: ctx.runId
});
},
transformOutput({ result }) {
// Log function output
Preview of the first 4,000 characters. Read full instructions →
Referenced files: 2 — file references are metadata, not package contents.
---
name: inngest-realtime
description: "Use when streaming durable workflow updates to a UI in real time — live order status pages that animate as steps complete, AI agent token streaming from a function to the browser, log tailing for long-running jobs, or human-in-the-loop approval flows that publish a prompt and wait for a user reply. Covers Inngest v4 native realtime: defining typed channels, publishing from inside step.run, minting subscription tokens via server actions, and consuming the stream from React/Next.js client components."
---
# Inngest Realtime
Stream updates from durable Inngest functions to live UIs. Use channels and topics to broadcast progress, render workflow execution as it happens, or build bi-directional human-in-the-loop flows.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
> **⚠ CRITICAL: v3 vs v4 package selection**
>
> Realtime in Inngest v4 lives at the SDK subpath `inngest/realtime`. The standalone `@inngest/realtime` npm package is a **v3-era package** and is **NOT compatible with `inngest@4.x`**. If your project is on v4 (the npm default), do not install `@inngest/realtime`. Use the imports below.
>
> Symptoms of using the wrong package on v4: `TypeError: Cls is not a constructor` on every `PUT /api/inngest`, 401 on subscription tokens, type incompatibility on `new Inngest({ middleware: [...] })`. Verify your `package.json` shows `"inngest": "^4.x"` before reading further.
## Prerequisites
- Inngest v4 SDK installed (`npm install inngest`) — see the `inngest-setup` skill
- `INNGEST_DEV=1` set in `.env.local` for local development (without it, the SDK demands cloud signing keys and 401s on token requests)
- Local Inngest dev server running (`npx inngest-cli@latest dev`)
- Optional: `zod` for schema validation on topics
## When to use Realtime
| Problem shape | Pattern |
|---|---|
| Order status page animates as durable workflow steps complete | Per-run channel, publish per step, client subscribes |
| AI agent streams tokens to a chat UI | Per-conversation channel, publish chunks, stream to browser |
| Log tail for a long-running job | Single channel, log topic, append to UI |
| Human-in-the-loop approval | Channel + waitForEvent, publish prompt, wait for response |
| Admin dashboard with live order list | Global admin channel, fan-out from each function |
## Architecture
Three pieces:
1. **Channel definition** — a typed contract for what gets published. Lives in shared module so both server and client can reference the same channel name.
2. **Publishing** — call `step.realtime.publish` between steps to wrap a durable publish, or `inngest.realtime.publish` inside `step.run` because you're already inside a memoized step. See "Which publish method to use" below.
3. **Subscribing** — server action mints a subscription token; React client uses the `useRealtime` hook (or the lower-level `subscribe()` API for non-React consumers).
## Step 1: Define a channel
Channels are pure data — no class hierarchy, no zod runtime required (but recommended for type safety). Define them once and import where needed.
```typescript
// src/inngest/channels.ts
import { channel } from 'inngest/realtime';
import { z } from 'zod';
// Per-run channel: each fulfill-order run publishes step updates to its own channel.
export const orderChannel = channel({
name: (orderId: string) => `order:${orderId}`,
topics: {
step: {
schema: z.object({
name: z.string(),
status: z.enum(['running', 'complete', 'failed']),
output: z.record(z.string(), z.unknown()).optional(),
ts: z.number(),
}),
},
},
});
// Global admin channel: fan-out for cross-cutting visibility.
export const adminChannel = channel({
name: 'admin',
topics: {
order: {
schema: z.object({
orderId: z.string(),
step:Preview of the first 4,000 characters. Read full instructions →
---
name: inngest-setup
description: Use when adding durable execution to a TypeScript project — building retry-safe webhook handlers, background jobs that survive crashes, scheduled tasks, or long-running workflows that outlive a single request. Covers Inngest SDK installation, client config, environment variables, serve endpoints (Next.js, Express, Hono, Fastify), connect-as-worker mode, and the local dev server.
---
# Inngest Setup
This skill sets up Inngest in a TypeScript project from scratch, covering installation, client configuration, connection modes, and local development.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
## Prerequisites
- Node.js 18+ (Node.js 22.4+ recommended for WebSocket support)
- TypeScript project
- Package manager (npm, yarn, pnpm, or bun)
## Step 1: Install the Inngest SDK
Install the `inngest` npm package in your project:
```bash
npm install inngest
# or
yarn add inngest
# or
pnpm add inngest
# or
bun add inngest
```
## Step 2: Create an Inngest Client
Create a shared client file that you'll import throughout your codebase:
```typescript
// src/inngest/client.ts
import { Inngest } from "inngest";
export const inngest = new Inngest({
id: "my-app" // Unique identifier for your application (hyphenated slug)
});
// IMPORTANT: v4 defaults to Cloud mode. For local dev, set INNGEST_DEV=1 env var.
// Without it, your serve endpoint will return 500 ("In cloud mode but no signing key").
// In production, set INNGEST_SIGNING_KEY (required for Cloud mode).
```
### Key Configuration Options
- **`id`** (required): Unique identifier for your app. Use a hyphenated slug like `"my-app"` or `"user-service"`
- **`eventKey`**: Event key for sending events (prefer `INNGEST_EVENT_KEY` env var)
- **`env`**: Environment name for Branch Environments
- **`isDev`**: Force Dev mode (`true`) or Cloud mode (`false`). **v4 defaults to Cloud mode**, so set `INNGEST_DEV=1` env var for local development. **Never hardcode `isDev: true` in source code** — it will silently break in production. Always use the env var.
- **`signingKey`**: Signing key for production (prefer `INNGEST_SIGNING_KEY` env var). Moved from `serve()` to client in v4
- **`signingKeyFallback`**: Fallback signing key for key rotation (prefer `INNGEST_SIGNING_KEY_FALLBACK` env var)
- **`baseUrl`**: Custom Inngest API base URL (prefer `INNGEST_BASE_URL` env var)
- **`logger`**: Custom logger instance (e.g. winston, pino) — enables `logger` in function context
- **`middleware`**: Array of middleware (see **inngest-middleware** skill)
### Typed Events with eventType()
```typescript
import { Inngest, eventType } from "inngest";
import { z } from "zod";
const signupCompleted = eventType("user/signup.completed", {
schema: z.object({
userId: z.string(),
email: z.string(),
plan: z.enum(["free", "pro"])
})
});
const orderPlaced = eventType("order/placed", {
schema: z.object({
orderId: z.string(),
amount: z.number()
})
});
export const inngest = new Inngest({ id: "my-app" });
// Use event types as triggers for full type safety:
inngest.createFunction(
{ id: "handle-signup", triggers: [signupCompleted] },
async ({ event }) => {
event.data.userId; /* typed as string */
}
);
// Use event types when sending events:
await inngest.send(
signupCompleted.create({
userId: "user_123",
email: "user@example.com",
plan: "pro"
})
);
```
### Environment Variables Setup
Set these environment variables in your `.env` file or deployment environment:
```env
# Required for production
INNGEST_EVENT_KEY=your-event-key-here
INNGEST_SIGNING_KEY=your-signing-key-here
# Force dev mode during local development
INNGEST_DEV=1
# Optional - custom dev server URL (default: http://localhost:8288)
INNGEST_BASE_URL=http://localhost:8288
```
**⚠️ Common Gotcha**: NePreview of the first 4,000 characters. Read full instructions →
---
name: inngest-steps
description: "Use when implementing delays that must survive process restarts (e.g., 24-hour cart abandonment, scheduled follow-ups), waiting for human approval or external events with timeouts (review gates, webhook callbacks, async API completion), polling external services without losing state on crashes, calling other functions and awaiting their results, memoizing expensive operations so they don't re-run on retry, or running async work in parallel inside a workflow. Covers Inngest step methods: step.run, step.sleep, step.waitForEvent, step.waitForSignal, step.sendEvent, step.invoke, step.ai, plus patterns for loops and parallel execution."
---
# Inngest Steps
Build robust, durable workflows with Inngest's step methods. Each step is a separate HTTP request that can be independently retried and monitored.
> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.
## Core Concept
**🔄 Critical: Each step re-runs your function from the beginning.** Put ALL non-deterministic code (API calls, DB queries, randomness) inside steps, never outside.
**📊 Step Limits:** Every function has a maximum of 1,000 steps and 4MB total step data.
```typescript
// ❌ WRONG - will run 4 times
export default inngest.createFunction(
{ id: "bad-example", triggers: [{ event: "test" }] },
async ({ step }) => {
console.log("This logs 4 times!"); // Outside step = bad
await step.run("a", () => console.log("a"));
await step.run("b", () => console.log("b"));
await step.run("c", () => console.log("c"));
}
);
// ✅ CORRECT - logs once each
export default inngest.createFunction(
{ id: "good-example", triggers: [{ event: "test" }] },
async ({ step }) => {
await step.run("log-hello", () => console.log("hello"));
await step.run("a", () => console.log("a"));
await step.run("b", () => console.log("b"));
await step.run("c", () => console.log("c"));
}
);
```
## step.run()
Execute retriable code as a step. **Each step ID can be reused** - Inngest automatically handles counters.
```typescript
// Basic usage
const result = await step.run("fetch-user", async () => {
const user = await db.user.findById(userId);
return user; // Always return useful data
});
// Synchronous code works too
const transformed = await step.run("transform-data", () => {
return processData(result);
});
// Side effects (no return needed)
await step.run("send-notification", async () => {
await sendEmail(user.email, "Welcome!");
});
```
**✅ DO:**
- Put ALL non-deterministic logic inside steps
- Return useful data for subsequent steps
- Reuse step IDs in loops (counters handled automatically)
**❌ DON'T:**
- Put deterministic logic in steps unnecessarily
- Forget that each step = separate HTTP request
## step.sleep()
Pause execution without using compute time.
```typescript
// Duration strings
await step.sleep("wait-24h", "24h");
await step.sleep("short-delay", "30s");
await step.sleep("weekly-pause", "7d");
// Use in workflows
await step.run("send-welcome", () => sendEmail(email));
await step.sleep("wait-for-engagement", "3d");
await step.run("send-followup", () => sendFollowupEmail(email));
```
## step.sleepUntil()
Sleep until a specific datetime.
```typescript
const reminderDate = new Date("2024-12-25T09:00:00Z");
await step.sleepUntil("wait-for-christmas", reminderDate);
// From event data
const scheduledTime = new Date(event.data.remind_at);
await step.sleepUntil("wait-for-scheduled-time", scheduledTime);
```
## step.waitForEvent()
**🚨 CRITICAL: waitForEvent ONLY catches events sent AFTER this step executes.**
- ❌ Event sent before waitForEvent runs → will NOT be caught
- ✅ Event sent after waitForEvent runs → will be caught
- Always check for `null` return (means timeout, event never arrived)
```typescript
// Basic event waiting with timeout
conPreview of the first 4,000 characters. Read full instructions →
---
name: inngest-v3-v4-migration
description: Use when upgrading an existing TypeScript codebase from Inngest SDK v3 to v4, or when fixing mixed v3/v4 API usage. Covers detecting current SDK usage, moving triggers into createFunction options, replacing EventSchemas with eventType/staticSchema, moving serve options to the client, updating realtime imports, rewriting step.invoke string IDs, checkpointing/serverless runtime settings, Connect option changes, and verification.
---
# Inngest v3 to v4 Migration
Use this skill when the user asks to upgrade Inngest, fix v3/v4 errors, migrate
realtime, or clean up a codebase that has mixed SDK patterns.
Primary reference:
https://www.inngest.com/docs/reference/typescript/v4/migrations/v3-to-v4
This skill is agent-first: detect actual usage first, make mechanical API
changes in a controlled order, then typecheck and run focused tests.
## When to Trigger
Use this skill for requests like:
- "Upgrade Inngest from v3 to v4"
- "Fix our Inngest v4 migration"
- "We're getting signing key required / cloud mode errors after upgrading"
- "`step.invoke` with a string function ID stopped working"
- "`@inngest/realtime` broke after installing `inngest@4`"
- "Move from EventSchemas to eventType"
- "Make this existing Inngest repo v4-compatible"
If the user asks for a broad codebase reliability audit first, use
`inngest-brownfield-audit` to choose scope, then return here for the v4 changes.
## Migration Scan
Start by locating all Inngest surfaces:
```bash
rg -n '"inngest"|"@inngest/realtime"|"@inngest/agent-kit"' package.json **/package.json
rg -n 'new Inngest|EventSchemas|eventType|staticSchema|createFunction\\(|serve\\(|connect\\(|step\\.invoke|referenceFunction|@inngest/realtime|realtimeMiddleware|useInngestSubscription|serveHost|rewriteGatewayEndpoint|logLevel|streaming:|signingKey|signingKeyFallback|baseUrl|INNGEST_DEV|INNGEST_SIGNING_KEY' .
```
Then classify the repo:
- **No Inngest yet:** use `inngest-setup`, not this migration skill.
- **v3 only:** migrate the SDK and all breaking changes together.
- **mixed v3/v4:** prioritize removing broken v3 APIs from v4 code.
- **v4 mostly done:** focus on missed runtime gotchas like local dev mode,
serverless `maxRuntime`, realtime package imports, and string `step.invoke`.
Before editing, record:
```text
Inngest migration scan:
- Current package versions:
- Client files:
- Serve/connect entrypoints:
- Functions using old trigger syntax:
- EventSchemas usage:
- Realtime v3 package usage:
- step.invoke string IDs:
- Serverless runtime constraints:
- Tests/checks available:
```
## Upgrade Order
1. Update package versions.
2. Fix client construction and local/prod mode.
3. Move serve options to the client.
4. Move triggers into `createFunction` options.
5. Replace `EventSchemas` with `eventType()` / `staticSchema()`.
6. Rewrite `step.invoke()` string IDs.
7. Migrate realtime from `@inngest/realtime` to v4 native APIs.
8. Update middleware and logging.
9. Configure checkpointing/serverless runtime.
10. Typecheck, run tests, and optionally sync with the dev server.
## Package and Environment
Install the latest v4 SDK:
```bash
npm install inngest@latest
# or pnpm add inngest@latest
# or yarn add inngest@latest
```
If the repo uses v3 realtime, remove `@inngest/realtime`; v4 realtime lives in
the `inngest` package and subpaths such as `inngest/realtime`, `inngest/react`,
and native `step.realtime` / `inngest.realtime`.
v4 defaults to Cloud mode. For local development, use an env var:
```bash
INNGEST_DEV=1 npm run dev
```
Do not hardcode `isDev: true` in source unless the repo's existing environment
pattern clearly scopes it to local-only code. Production should use
`INNGEST_SIGNING_KEY`.
## Client and Serve Options
In v4, options such as `signingKey`, `signingKeyFallback`, and `baseUrl` belong
on `new Inngest(...)`, not on `serve(...)`.
```typescript
// Old v3
app.use(
"/api/inngest",
serve({
client: inngest,
functions,Preview of the first 4,000 characters. Read full instructions →
Publisher declarations from the archived package. These are separate from our research and the live service's terms.
Package observed Nov 10, 2026.
plugin_asdk_app_6abe99ad4764819183b795f0d74e5216
Download plugin data (JSON)Plugin details: freshly prepared. Prepared . Refreshed when plugin data changes or after 6 hours. Your account and Follow status are live.