← InngestCONTENT HISTORY
WHAT CHANGED
Update to Inngest
Snapshot Oct 24, 2026 · 13:41 UTC · version 0.4.1
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save Inngest and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"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.",
"included_files": [],
"name": "inngest-setup",
"skill_md_contents": "---\nname: inngest-setup\ndescription: 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.\n---\n\n# Inngest Setup\n\nThis skill sets up Inngest in a TypeScript project from scratch, covering installation, client configuration, connection modes, and local development.\n\n> **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.\n\n## Prerequisites\n\n- Node.js 18+ (Node.js 22.4+ recommended for WebSocket support)\n- TypeScript project\n- Package manager (npm, yarn, pnpm, or bun)\n\n## Step 1: Install the Inngest SDK\n\nInstall the `inngest` npm package in your project:\n\n```bash\nnpm install inngest\n# or\nyarn add inngest\n# or\npnpm add inngest\n# or\nbun add inngest\n```\n\n## Step 2: Create an Inngest Client\n\nCreate a shared client file that you'll import throughout your codebase:\n\n```typescript\n// src/inngest/client.ts\nimport { Inngest } from \"inngest\";\n\nexport const inngest = new Inngest({\n id: \"my-app\" // Unique identifier for your application (hyphenated slug)\n});\n// IMPORTANT: v4 defaults to Cloud mode. For local dev, set INNGEST_DEV=1 env var.\n// Without it, your serve endpoint will return 500 (\"In cloud mode but no signing key\").\n// In production, set INNGEST_SIGNING_KEY (required for Cloud mode).\n```\n\n### Key Configuration Options\n\n- **`id`** (required): Unique identifier for your app. Use a hyphenated slug like `\"my-app\"` or `\"user-service\"`\n- **`eventKey`**: Event key for sending events (prefer `INNGEST_EVENT_KEY` env var)\n- **`env`**: Environment name for Branch Environments\n- **`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.\n- **`signingKey`**: Signing key for production (prefer `INNGEST_SIGNING_KEY` env var). Moved from `serve()` to client in v4\n- **`signingKeyFallback`**: Fallback signing key for key rotation (prefer `INNGEST_SIGNING_KEY_FALLBACK` env var)\n- **`baseUrl`**: Custom Inngest API base URL (prefer `INNGEST_BASE_URL` env var)\n- **`logger`**: Custom logger instance (e.g. winston, pino) — enables `logger` in function context\n- **`middleware`**: Array of middleware (see **inngest-middleware** skill)\n\n### Typed Events with eventType()\n\n```typescript\nimport { Inngest, eventType } from \"inngest\";\nimport { z } from \"zod\";\n\nconst signupCompleted = eventType(\"user/signup.completed\", {\n schema: z.object({\n userId: z.string(),\n email: z.string(),\n plan: z.enum([\"free\", \"pro\"])\n })\n});\n\nconst orderPlaced = eventType(\"order/placed\", {\n schema: z.object({\n orderId: z.string(),\n amount: z.number()\n })\n});\n\nexport const inngest = new Inngest({ id: \"my-app\" });\n\n// Use event types as triggers for full type safety:\ninngest.createFunction(\n { id: \"handle-signup\", triggers: [signupCompleted] },\n async ({ event }) => {\n event.data.userId; /* typed as string */\n }\n);\n\n// Use event types when sending events:\nawait inngest.send(\n signupCompleted.create({\n userId: \"user_123\",\n email: \"user@example.com\",\n plan: \"pro\"\n })\n);\n```\n\n### Environment Variables Setup\n\nSet these environment variables in your `.env` file or deployment environment:\n\n```env\n# Required for production\nINNGEST_EVENT_KEY=your-event-key-here\nINNGEST_SIGNING_KEY=your-signing-key-here\n\n# Force dev mode during local development\nINNGEST_DEV=1\n\n# Optional - custom dev server URL (default: http://localhost:8288)\nINNGEST_BASE_URL=http://localhost:8288\n```\n\n**⚠️ Common Gotcha**: Never hardcode keys in your source code. Always use environment variables for `INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY`.\n\n## CRITICAL: Enable Dev Mode for Local Development\n\n**Before creating serve endpoints or connecting workers, ensure dev mode is enabled.** Without it, Inngest defaults to Cloud mode and your endpoints will fail with 500 errors.\n\nAdd to your `.env` file (or your dev script in package.json):\n\n```env\nINNGEST_DEV=1\n```\n\nOr in `package.json` scripts:\n\n```json\n{\n \"scripts\": {\n \"dev\": \"INNGEST_DEV=1 tsx --watch src/server.ts\"\n }\n}\n```\n\n**Symptoms of missing INNGEST_DEV:**\n- GET `/api/inngest` returns `{\"code\":\"internal_server_error\"}`\n- Server logs: \"In cloud mode but no signing key found\"\n- Dev server can't sync with your app\n\n## Step 3: Choose Your Connection Mode\n\nInngest supports two connection modes:\n\n### Mode A: Serve Endpoint (HTTP)\n\nBest for serverless platforms (Vercel, Lambda, etc.) and existing APIs.\n\n### Mode B: Connect (WebSocket)\n\nBest for container runtimes (Kubernetes, Docker) and long-running processes.\n\n## Step 4A: Serving an Endpoint (HTTP Mode)\n\nCreate an API endpoint that exposes your functions to Inngest:\n\n```typescript\n// For Next.js App Router: src/app/api/inngest/route.ts\nimport { serve } from \"inngest/next\";\nimport { inngest } from \"../../../inngest/client\";\nimport { myFunction } from \"../../../inngest/functions\";\n\nexport const { GET, POST, PUT } = serve({\n client: inngest,\n functions: [myFunction]\n});\n```\n\n```typescript\n// For Next.js Pages Router: pages/api/inngest.ts\nimport { serve } from \"inngest/next\";\nimport { inngest } from \"../../inngest/client\";\nimport { myFunction } from \"../../inngest/functions\";\n\nexport default serve({\n client: inngest,\n functions: [myFunction]\n});\n```\n\n```typescript\n// For Express.js\nimport express from \"express\";\nimport { serve } from \"inngest/express\";\nimport { inngest } from \"./inngest/client\";\nimport { myFunction } from \"./inngest/functions\";\n\nconst app = express();\napp.use(express.json({ limit: \"10mb\" })); // Required for Inngest, increase limit for larger function state\n\napp.use(\n \"/api/inngest\",\n serve({\n client: inngest,\n functions: [myFunction]\n })\n);\n```\n\n**🔧 Framework-Specific Notes**:\n\n- **Express**: Must use `express.json({ limit: \"10mb\" })` middleware to support larger function state.\n- **Fastify**: Use `fastifyPlugin` from `inngest/fastify`\n- **Cloudflare Workers**: Use `inngest/cloudflare`\n- **AWS Lambda**: Use `inngest/lambda`\n- For all other frameworks, check the `serve` reference here: https://www.inngest.com/docs-markdown/learn/serving-inngest-functions\n\n**⚠️ v4 Change:** Options like `signingKey`, `signingKeyFallback`, and `baseUrl` are now configured on the `Inngest` client constructor, not on `serve()`. The `serve()` function only accepts `client`, `functions`, and `streaming`.\n\n**⚠️ Common Gotcha**: Always use `/api/inngest` as your endpoint path. This enables automatic discovery. If you must use a different path, you'll need to configure discovery manually with the `-u` flag.\n\n## Step 4B: Connect as Worker (WebSocket Mode)\n\nFor long-running applications that maintain persistent connections:\n\n```typescript\n// src/worker.ts\nimport { connect } from \"inngest/connect\";\nimport { inngest } from \"./inngest/client\";\nimport { myFunction } from \"./inngest/functions\";\n\n(async () => {\n const connection = await connect({\n apps: [{ client: inngest, functions: [myFunction] }],\n instanceId: process.env.HOSTNAME, // Unique worker identifier\n maxWorkerConcurrency: 10 // Max concurrent steps\n });\n\n console.log(\"Worker connected:\", connection.state);\n\n // Graceful shutdown handling\n await connection.closed;\n console.log(\"Worker shut down\");\n})();\n```\n\n**Requirements for Connect Mode**:\n\n- Node.js 22.4+ (or Deno 1.4+, Bun 1.1+) for WebSocket support\n- Long-running server environment (not serverless)\n- `INNGEST_SIGNING_KEY` and `INNGEST_EVENT_KEY` for production\n- Set the `appVersion` parameter on the `Inngest` client for production to support rolling deploys\n\n**v4 Connect Changes:**\n\n- **Worker thread isolation** is enabled by default — WebSocket connections execute in a worker thread to prevent event loop starvation. Set `isolateExecution: false` to use a single process (or `INNGEST_CONNECT_ISOLATE_EXECUTION=false`)\n- **`rewriteGatewayEndpoint`** callback has been replaced with the `gatewayUrl` string option (or `INNGEST_CONNECT_GATEWAY_URL` env var)\n\n## Step 5: Organizing with Apps\n\nAs your system grows, organize functions into logical apps:\n\n```typescript\n// User service\nconst userService = new Inngest({ id: \"user-service\" });\n\n// Payment service\nconst paymentService = new Inngest({ id: \"payment-service\" });\n\n// Email service\nconst emailService = new Inngest({ id: \"email-service\" });\n```\n\nEach app gets its own section in the Inngest dashboard and can be deployed independently. Use descriptive, hyphenated IDs that match your service architecture.\n\n**⚠️ Common Gotcha**: Changing an app's `id` creates a new app in Inngest. Keep IDs consistent across deployments.\n\n## Step 6: Local Development with inngest-cli\n\nStart the Inngest Dev Server for local development:\n\n```bash\n# Auto-discover your app on common ports/endpoints\nnpx --ignore-scripts=false inngest-cli@latest dev\n\n# Specify your app's URL manually\nnpx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest\n\n# Custom port for dev server\nnpx --ignore-scripts=false inngest-cli@latest dev -p 9999\n\n# Disable auto-discovery\nnpx --ignore-scripts=false inngest-cli@latest dev --no-discovery -u http://localhost:3000/api/inngest\n\n# Multiple apps\nnpx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest -u http://localhost:4000/api/inngest\n```\n\nThe dev server will be available at `http://localhost:8288` by default.\n\n### Configuration File (Optional)\n\nCreate `inngest.json` for complex setups:\n\n```json\n{\n \"sdk-url\": [\n \"http://localhost:3000/api/inngest\",\n \"http://localhost:4000/api/inngest\"\n ],\n \"port\": 8289,\n \"no-discovery\": true\n}\n```\n\n## Environment-Specific Setup\n\n### Local Development\n\n```env\nINNGEST_DEV=1\n# No keys required in dev mode\n```\n\n### Production\n\n```env\nINNGEST_EVENT_KEY=evt_your_production_event_key\nINNGEST_SIGNING_KEY=signkey_your_production_signing_key\n```\n\n### Custom Dev Server Port\n\n```env\nINNGEST_DEV=1\nINNGEST_BASE_URL=http://localhost:9999\n```\n\nIf your app runs on a non-standard port (not 3000), make sure the dev server can reach it by specifying the URL with `-u` flag.\n\n## Common Issues & Solutions\n\n**Port Conflicts**: If port 8288 is in use, specify a different port: `-p 9999`\n\n**Auto-discovery Not Working**: Use manual URL specification: `-u http://localhost:YOUR_PORT/api/inngest`. If using `--no-discovery` flag, the `-u` flag is **required** — the dev server will not find your app without it.\n\n**Functions Not Showing in Dev Server**: Your app must register with the dev server. This happens automatically when your serve endpoint receives its first request from the dev server. If registration isn't happening: (1) verify `INNGEST_DEV=1` is set, (2) verify the dev server can reach your app URL, (3) try restarting your app while the dev server is running.\n\n**Signature Verification Errors**: Ensure `INNGEST_SIGNING_KEY` is set correctly in production\n\n**WebSocket Connection Issues**: Verify Node.js version 22.4+ for connect mode\n\n**Docker Development**: Use `host.docker.internal` for app URLs when running dev server in Docker\n\n## Next Steps\n\n1. Create your first Inngest function with `inngest.createFunction()`\n2. Test functions using the dev server's \"Invoke\" button\n3. Send events with `inngest.send()` to trigger functions\n4. Deploy to production with proper environment variables\n5. See **inngest-middleware** for adding logging, error tracking, and other cross-cutting concerns\n6. Monitor functions in the Inngest dashboard\n\nThe dev server automatically reloads when you change functions, making development fast and iterative.\n"
}SHA-256 of public snapshot: bc74510119b09c84f7510760e102e173d2bcec997681ee3aaea3e429a74bb7c4