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 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
, use
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
for the CLI even in Bun projects.
— Local Dev Server
Starts an in-memory local version of Inngest with a browser UI at
.
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 |
|---|
| | http://localhost:3000/api/inngest
| App serve endpoint URL(s) |
| | | Dev Server port |
| | | Dev Server host |
| | | Disable auto-discovery of apps |
| | | Disable polling apps for changes |
| | | Path to configuration file |
| | | Connect gateway endpoint port |
| | | Persist data between restarts |
| | | Seconds between app polling checks |
| | | Number of executor workers |
| | | Linear retry interval in seconds |
| | | Executor queue polling interval in milliseconds |
Auto-Discovery
Without
, the Dev Server scans common ports and endpoints automatically:
Ports scanned: Common development ports including 3000, 3030, and others
Endpoints scanned:
/.netlify/functions/inngest
/.redwood/functions/inngest
Configuration File
Create an
(or
,
) 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 |
|---|
| enables Dev Mode (disables signature verification). forces Cloud mode. Accepts a URL (e.g., ). Defaults to Cloud mode if unset. |
| Host for SDK-to-Inngest communication (e.g., ). Leave unset in most cases. |
| Authentication key for sending events. Use any dummy value locally — Dev Server does not validate. |
| Secures requests between Inngest and your app. Required in production. Determines which Inngest environment receives syncs. |
INNGEST_SIGNING_KEY_FALLBACK
| Fallback key for signing key rotation (v3.18.0+). |
| Full origin URL for Inngest to reach your app (e.g., ). Auto-inferred from request headers; set explicitly for AWS Lambda, proxies, or tunnels. |
| URL path to your serve endpoint (e.g., ). Auto-inferred in most cases. |
| Enable response streaming (/). Extends timeout limits on Vercel and edge runtimes. |
| Target Inngest Environment. Auto-detected on some platforms. |
Debugging Your Serve Endpoint
Verify your
endpoint is configured correctly:
bash
curl -s http://localhost:3000/api/inngest | jq
json
{
"message": "Inngest endpoint configured correctly.",
"hasEventKey": false,
"hasSigningKey": false,
"functionsFound": 3
}
If
is
, check that your functions are passed to the
call.
Testing Functions Locally
Send Events via SDK
typescript
import { Inngest } from "inngest";
const inngest = new Inngest({ id: "my-app" });
await inngest.send({
name: "user/signup.completed",
data: {
userId: "user_123",
email: "user@example.com",
},
});
Send Events via curl
bash
curl -X POST "http://localhost:8288/e/test" \
-H "Content-Type: application/json" \
-d '{
"name": "user/signup.completed",
"data": {
"userId": "user_123",
"email": "user@example.com"
}
}'
The event key in the URL path (
above) can be any value locally.
Unit Testing with
bash
npm install -D @inngest/test
typescript
import { InngestTestEngine } from "@inngest/test";
import { helloWorld } from "./functions";
// Execute full function
const t = new InngestTestEngine({ function: helloWorld });
const { result } = await t.execute();
expect(result).toEqual("Hello World!");
// Test a single step
const { result: stepResult } = await t.executeStep("calculate-price");
expect(stepResult).toEqual(123);
// Assert step state
const { state } = await t.execute();
await expect(state["my-step"]).resolves.toEqual("output");
await expect(state["risky-step"]).rejects.toThrowError("failed");
// Mock events
const { result: eventResult } = await t.execute({
events: [{ name: "demo/event.sent", data: { message: "Hi!" } }],
});
// Mock step responses
const { result: mockResult } = await t.execute({
steps: [{ id: "external-api-call", handler() { return { status: "ok" }; } }],
});
// Mock sleep/waitForEvent (pause-inducing steps require mocking)
await t.execute({
steps: [{ id: "wait-one-day", handler() {} }],
});
Mock external dependencies with your test framework's standard mocking (
,
, etc.) —
handles only Inngest-specific mocking.
Docker Setup
Standalone
bash
docker run -p 8288:8288 -p 8289:8289 \
inngest/inngest \
inngest dev -u http://host.docker.internal:3000/api/inngest
Use
to reach your app running on the host machine (works out of the box on Docker Desktop). On Linux, add
--add-host=host.docker.internal:host-gateway
or use an equivalent host-access method.
Docker Compose
yaml
services:
app:
build: ./app
environment:
- INNGEST_DEV=1
- INNGEST_BASE_URL=http://inngest:8288
ports:
- "3000:3000"
inngest:
image: inngest/inngest
command: "inngest dev -u http://app:3000/api/inngest"
ports:
- "8288:8288"
- "8289:8289"
Port 8288 is the main server and UI.
Port 8289 is the
WebSocket gateway.
Critical: Set
on your app — the TypeScript SDK defaults to Cloud mode, which will skip the Dev Server.
MCP Server (AI Dev Tools)
The Dev Server exposes an MCP server at
http://127.0.0.1:8288/mcp
(HTTP transport).
bash
# Claude Code
claude mcp add --transport http inngest-dev http://127.0.0.1:8288/mcp
json
// .cursor/mcp.json or another MCP-capable client config
{
"mcpServers": {
"inngest-dev": {
"url": "http://127.0.0.1:8288/mcp"
}
}
}
Available MCP Tools
| Tool | Description |
|---|
| Send events to trigger functions |
| List all registered functions and triggers |
| Execute a function synchronously (default 30s timeout) |
| Get detailed status of a function run |
| Poll multiple runs until completion |
| Search Inngest documentation by regex pattern |
| Read a specific documentation page |
| List available documentation structure |
— Self-Hosted Production
Runs Inngest as a self-hosted production server.
Not the same as — this is for production workloads.
bash
inngest start --event-key <key> --signing-key <key>
| Flag | Short | Default | Description |
|---|
| | | Server port |
| | | Hex key for request signing (even character count) |
| | | Authentication key for apps (repeatable) |
| | | App serve URLs (repeatable) |
| | | External Redis connection |
| | | External PostgreSQL connection |
| | | SQLite database directory |
| | | App sync polling interval (seconds) |
| | | Number of executor workers |
| | | Connect gateway port |
| | | Linear retry interval in seconds |
| | | Executor queue polling interval in milliseconds |
| | | Disable web UI and GraphQL API |
--postgres-conn-max-idle-time
| | | PostgreSQL idle connection lifetime in minutes |
--postgres-conn-max-lifetime
| | | PostgreSQL maximum connection reuse time in minutes |
--postgres-max-idle-conns
| | | PostgreSQL max idle connections |
--postgres-max-open-conns
| | | PostgreSQL max open connections |
Global flags such as
,
, and
are also available. For environment variables, follow the current CLI and deployment docs; do not assume every flag has an
environment variable equivalent.
Default persistence: in-memory Redis + SQLite at
. For production, use external Redis and PostgreSQL.
Deployment Workflow
Local Development → Production
- Develop locally with — no keys needed, no code changes for production
- Deploy your app to your hosting platform
- Sync with Inngest using one of three methods:
bash
# Option 1: Curl from CI/CD
curl -X PUT https://your-app.com/api/inngest --fail-with-body
# Option 2: Vercel/Netlify integrations (automatic on deploy)
# Option 3: Manual sync via Inngest Cloud dashboard
- Set environment variables in production:
bash
INNGEST_EVENT_KEY=<your-event-key>
INNGEST_SIGNING_KEY=<your-signing-key>
No code changes are needed when moving from local dev to production. The SDK automatically detects the environment.
Platform-Specific Gotchas
| Platform | Gotcha |
|---|
| Express | Requires middleware; default body limit is — increase to handle Inngest payloads (up to 4MB) |
| AWS Lambda | Set and explicitly — auto-inference fails |
| Firebase Cloud Functions | Must set env var |
| DigitalOcean Functions | Both and required in config |
| Cloudflare Workers (Wrangler ) | Requires tunnel (ngrok/localtunnel) for Dev Server connection |
| Supabase Edge Functions | must match function name — Supabase rewrites request paths |
| Google Cloud Run (1st gen) | Not officially supported; may cause signature verification errors |
| Docker | Must set — SDK defaults to Cloud mode |
| External webhooks (Stripe, Clerk) | Require tunnel solution (ngrok, localtunnel) for local testing |
Quick Reference
bash
# Start dev server with auto-discovery
npx inngest-cli@latest dev
# Start with explicit app URL
npx inngest-cli@latest dev -u http://localhost:3000/api/inngest
# Check serve endpoint health
curl -s http://localhost:3000/api/inngest | jq
# Send test event via curl
curl -X POST http://localhost:8288/e/test -d '{"name": "test/event", "data": {}}'
# Sync after deploy (CI/CD)
curl -X PUT https://your-app.com/api/inngest --fail-with-body
# Self-hosted production
inngest start --event-key <key> --signing-key <key>
Troubleshooting
| Issue | Cause | Solution |
|---|
| Dev Server doesn't find functions | App not running or wrong port | Start your app first; use to specify the correct URL |
| in debug output | Functions not passed to | Verify all functions are in the array passed to |
| SDK connects to Cloud instead of Dev Server | not set | Set in your environment |
| Functions sync to wrong Inngest environment | Wrong signing key | Check matches target environment |
| Duplicate app in Inngest dashboard | App was changed | Keep the in stable across deploys |
| Webhook events not reaching Dev Server | No tunnel configured | Use ngrok or localtunnel for external webhook sources |
| "Unattached sync" in dashboard | Auto-sync failed silently | Check integration logs; resync manually |
See inngest-setup for SDK installation and inngest-durable-functions for function configuration.