inngest-cli — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited inngest-cli (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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 inngest api, use inngest-api-cli when available.
# 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/inngestIf 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 ServerStarts an in-memory local version of Inngest with a browser UI at http://localhost:8288.
# 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| 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 |
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/inngestCreate an inngest.json (or .yaml, .toml) in your project root. The CLI walks up directories to find it.
{
"sdk-url": [
"http://localhost:3000/api/inngest",
"http://localhost:3030/api/inngest"
],
"no-discovery": true
}# inngest.yaml
sdk-url:
- "http://localhost:3000/api/inngest"
- "http://localhost:3030/api/inngest"
no-discovery: true| 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 for SDK-to-Inngest communication (e.g., http://localhost:8288). Leave unset in most cases. |
INNGEST_EVENT_KEY | Authentication key for sending events. Use any dummy value locally — Dev Server does not validate. |
INNGEST_SIGNING_KEY | 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+). |
INNGEST_SERVE_ORIGIN | Full origin URL for Inngest to reach your app (e.g., https://my-app.com). Auto-inferred from request headers; set explicitly for AWS Lambda, proxies, or tunnels. |
INNGEST_SERVE_PATH | URL path to your serve endpoint (e.g., /api/inngest). Auto-inferred in most cases. |
INNGEST_STREAMING | Enable response streaming (true/false). Extends timeout limits on Vercel and edge runtimes. |
INNGEST_ENV | Target Inngest Environment. Auto-detected on some platforms. |
Verify your serve() endpoint is configured correctly:
curl -s http://localhost:3000/api/inngest | jq{
"message": "Inngest endpoint configured correctly.",
"hasEventKey": false,
"hasSigningKey": false,
"functionsFound": 3
}If functionsFound is 0, check that your functions are passed to the serve() call.
import { Inngest } from "inngest";
const inngest = new Inngest({ id: "my-app" });
await inngest.send({
name: "user/signup.completed",
data: {
userId: "user_123",
email: "[email protected]",
},
});curl -X POST "http://localhost:8288/e/test" \
-H "Content-Type: application/json" \
-d '{
"name": "user/signup.completed",
"data": {
"userId": "user_123",
"email": "[email protected]"
}
}'The event key in the URL path (test above) can be any value locally.
@inngest/testRequires inngest@>=4.0.0.
npm install -D @inngest/testimport { 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 (jest.mock, vi.mock, etc.) — @inngest/test handles only Inngest-specific mocking.
docker run -p 8288:8288 -p 8289:8289 \
inngest/inngest \
inngest dev -u http://host.docker.internal:3000/api/inngestUse host.docker.internal 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.
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 connect() WebSocket gateway.
Critical: Set INNGEST_DEV=1 on your app — the TypeScript SDK defaults to Cloud mode, which will skip the Dev Server.
The Dev Server exposes an MCP server at http://127.0.0.1:8288/mcp (HTTP transport).
# Claude Code
claude mcp add --transport http inngest-dev http://127.0.0.1:8288/mcp// .cursor/mcp.json or another MCP-capable client config
{
"mcpServers": {
"inngest-dev": {
"url": "http://127.0.0.1:8288/mcp"
}
}
}| Tool | Description |
|---|---|
send_event | Send events to trigger functions |
list_functions | List all registered functions and triggers |
invoke_function | Execute a function synchronously (default 30s timeout) |
get_run_status | Get detailed status of a function run |
poll_run_status | Poll multiple runs until completion |
grep_docs | Search Inngest documentation by regex pattern |
read_doc | Read a specific documentation page |
list_docs | List available documentation structure |
inngest start — Self-Hosted ProductionRuns Inngest as a self-hosted production server. Not the same as `inngest dev` — this is for production workloads.
inngest start --event-key <key> --signing-key <key>| Flag | Short | Default | Description |
|---|---|---|---|
--port | -p | 8288 | Server port |
--signing-key | Hex key for request signing (even character count) | ||
--event-key | Authentication key for apps (repeatable) | ||
--sdk-url | -u | App serve URLs (repeatable) | |
--redis-uri | External Redis connection | ||
--postgres-uri | External PostgreSQL connection | ||
--sqlite-dir | SQLite database directory | ||
--poll-interval | 0 | App sync polling interval (seconds) | |
--queue-workers | 100 | Number of executor workers | |
--connect-gateway-port | 8289 | Connect gateway port | |
--retry-interval | 0 | Linear retry interval in seconds | |
--tick | 150 | Executor queue polling interval in milliseconds | |
--no-ui | Disable web UI and GraphQL API | ||
--postgres-conn-max-idle-time | 5 | PostgreSQL idle connection lifetime in minutes | |
--postgres-conn-max-lifetime | 30 | PostgreSQL maximum connection reuse time in minutes | |
--postgres-max-idle-conns | 10 | PostgreSQL max idle connections | |
--postgres-max-open-conns | 100 | PostgreSQL max open connections |
Global flags such as --log-level, --verbose, and --json are also available. For environment variables, follow the current CLI and deployment docs; do not assume every flag has an INNGEST_ environment variable equivalent.
Default persistence: in-memory Redis + SQLite at ./.inngest/main.db. For production, use external Redis and PostgreSQL.
inngest dev — no keys needed, no code changes for production# 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 dashboardINNGEST_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 | Gotcha |
|---|---|
| Express | Requires express.json() middleware; default body limit is 100kb — increase to handle Inngest payloads (up to 4MB) |
| AWS Lambda | Set INNGEST_SERVE_ORIGIN and INNGEST_SERVE_PATH explicitly — auto-inference fails |
| Firebase Cloud Functions | Must set INNGEST_SERVE_PATH env var |
| DigitalOcean Functions | Both serveOrigin and servePath required in serve() config |
| Cloudflare Workers (Wrangler `--remote`) | Requires tunnel (ngrok/localtunnel) for Dev Server connection |
| Supabase Edge Functions | servePath must match function name — Supabase rewrites request paths |
| Google Cloud Run (1st gen) | Not officially supported; may cause signature verification errors |
| Docker | Must set INNGEST_DEV=1 — SDK defaults to Cloud mode |
| External webhooks (Stripe, Clerk) | Require tunnel solution (ngrok, localtunnel) for local testing |
# 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>| Issue | Cause | Solution |
|---|---|---|
| Dev Server doesn't find functions | App not running or wrong port | Start your app first; use -u to specify the correct URL |
functionsFound: 0 in debug output | Functions not passed to serve() | Verify all functions are in the array passed to serve() |
| SDK connects to Cloud instead of Dev Server | INNGEST_DEV not set | Set INNGEST_DEV=1 in your environment |
| Functions sync to wrong Inngest environment | Wrong signing key | Check INNGEST_SIGNING_KEY matches target environment |
| Duplicate app in Inngest dashboard | App id was changed | Keep the id in new Inngest({ id }) 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.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.