{"id":"6e3d6c91-382b-4cdb-9bc3-bbc51e725d58","shortId":"3rLvbL","kind":"skill","title":"inngest-middleware","tagline":"Create and use Inngest middleware for cross-cutting concerns. Covers the middleware lifecycle, creating custom middleware, dependency injection with dependencyInjectionMiddleware, encryption via @inngest/middleware-encryption, Sentry error tracking via @inngest/middleware-sentry,","description":"# Inngest Middleware\n\nMaster 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.\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> **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.\n\n## What is Middleware?\n\nMiddleware 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.\n\n**When to use middleware:**\n\n- **Observability:** Add logging, tracing, or metrics\n- **Dependency injection:** Share client instances across functions\n- **Data transformation:** Encrypt/decrypt, validate, or enrich data\n- **Error handling:** Custom error tracking and alerting\n- **Authentication:** Validate user context or permissions\n\n## Middleware Lifecycle\n\nMiddleware can be registered at **client-level** (affects all functions) or **function-level** (affects specific functions).\n\n### Execution Order\n\n```typescript\nconst inngest = new Inngest({\n  id: \"my-app\",\n  middleware: [\n    loggingMiddleware, // Runs 1st\n    errorMiddleware // Runs 2nd\n  ]\n});\n\ninngest.createFunction(\n  {\n    id: \"example\",\n    middleware: [\n      authMiddleware, // Runs 3rd\n      metricsMiddleware // Runs 4th\n    ],\n    triggers: [{ event: \"test\" }]\n  },\n  async () => {\n    /* function code */\n  }\n);\n```\n\n**Order matters:** Client middleware runs first, then function middleware, in the order specified.\n\n## Creating Custom Middleware\n\n### Basic Middleware Structure\n\n```typescript\nimport { InngestMiddleware } from \"inngest\";\n\nconst loggingMiddleware = new InngestMiddleware({\n  name: \"Logging Middleware\",\n  init() {\n    // Setup phase - runs when client initializes\n    const logger = setupLogger();\n\n    return {\n      // Function execution lifecycle\n      // Note: `fn` is loosely typed in middleware generics; fn.id works at runtime\n      onFunctionRun({ ctx, fn }) {\n        return {\n          beforeExecution() {\n            logger.info(\"Function starting\", {\n              functionId: fn.id,\n              eventName: ctx.event.name,\n              runId: ctx.runId\n            });\n          },\n\n          afterExecution() {\n            logger.info(\"Function completed\", {\n              functionId: fn.id,\n              runId: ctx.runId\n            });\n          },\n\n          transformOutput({ result }) {\n            // Log function output\n            logger.debug(\"Function output\", {\n              functionId: fn.id,\n              output: result.data\n            });\n\n            // Return unmodified result\n            return { result };\n          }\n        };\n      },\n\n      // Event sending lifecycle\n      onSendEvent() {\n        return {\n          transformInput({ payloads }) {\n            logger.info(\"Sending events\", {\n              count: payloads.length,\n              events: payloads.map((p) => p.name)\n            });\n\n            // Spread to convert readonly array to mutable array\n            return { payloads: [...payloads] };\n          }\n        };\n      }\n    };\n  }\n});\n```\n\n### Python Implementation\n\nPython middleware follows a similar pattern. See [Dependency Injection Reference](./references/dependency-injection.md) for complete Python examples.\n\n````\n\n## Dependency Injection\n\nShare expensive or stateful clients across all functions. **See [Dependency Injection Reference](./references/dependency-injection.md) for detailed patterns.**\n\n### Quick Example - Built-in DI\n\n```typescript\nimport { dependencyInjectionMiddleware } from \"inngest\";\n\nconst inngest = new Inngest({\n  id: 'my-app',\n  middleware: [\n    dependencyInjectionMiddleware({\n      openai: new OpenAI(),\n      db: new PrismaClient(),\n    }),\n  ],\n});\n\n// Functions automatically get injected dependencies\ninngest.createFunction(\n  { id: \"ai-summary\", triggers: [{ event: \"document/uploaded\" }] },\n  async ({ event, openai, db }) => {\n    // Dependencies available in function context\n    const summary = await openai.chat.completions.create({\n      messages: [{ role: \"user\", content: event.data.content }],\n      model: \"gpt-4\",\n    });\n\n    await db.document.update({\n      where: { id: event.data.documentId },\n      data: { summary: summary.choices[0].message.content }\n    });\n  }\n);\n````\n\n## Middleware Packages\n\nBeyond `dependencyInjectionMiddleware` (built-in, shown above), Inngest provides official middleware as **separate packages**. **See [Middleware Reference](./references/built-in-middleware.md) for complete details.**\n\n### Encryption Middleware\n\n```bash\nnpm install @inngest/middleware-encryption\n```\n\n```typescript\nimport { encryptionMiddleware } from \"@inngest/middleware-encryption\";\n\nconst inngest = new Inngest({\n  id: \"my-app\",\n  middleware: [\n    encryptionMiddleware({\n      key: process.env.ENCRYPTION_KEY\n    })\n  ]\n});\n```\n\nAutomatically encrypts all step data, function output, and event `data.encrypted` field. Supports key rotation via `fallbackDecryptionKeys`.\n\n### Sentry Error Tracking\n\n```bash\nnpm install @inngest/middleware-sentry\n```\n\n```typescript\nimport * as Sentry from \"@sentry/node\";\nimport { sentryMiddleware } from \"@inngest/middleware-sentry\";\n\nSentry.init({\n  /* your Sentry config */\n});\n\nconst inngest = new Inngest({\n  id: \"my-app\",\n  middleware: [sentryMiddleware()]\n});\n```\n\nCaptures exceptions, adds tracing to each function run, and includes function ID and event names as context. Requires `@sentry/*@>=8.0.0`.\n\n## Common Middleware Patterns\n\n### Metrics and Performance Tracking\n\n```typescript\nconst metricsMiddleware = new InngestMiddleware({\n  name: \"Metrics Tracking\",\n  init() {\n    return {\n      onFunctionRun({ ctx, fn }) {\n        let startTime: number;\n\n        return {\n          beforeExecution() {\n            startTime = Date.now();\n            metrics.increment(\"inngest.step.started\", {\n              function: fn.id,\n              event: ctx.event.name\n            });\n          },\n\n          afterExecution() {\n            const duration = Date.now() - startTime;\n            metrics.histogram(\"inngest.step.duration\", duration, {\n              function: fn.id,\n              event: ctx.event.name\n            });\n          },\n\n          transformOutput({ result }) {\n            const status = result.error ? \"error\" : \"success\";\n            metrics.increment(\"inngest.step.completed\", {\n              function: fn.id,\n              status: status\n            });\n\n            return { result };\n          }\n        };\n      }\n    };\n  }\n});\n```\n\n### Advanced Patterns\n\n**Authentication:** Validate tokens and inject user context\n**Conditional logic:** Apply middleware based on event type or function\n**Circuit breakers:** Prevent cascading failures from external services\n\n### Configuration-Based Middleware\n\nCreate reusable middleware with configuration options for different environments and use cases. See reference documentation for complete examples.\n\n## Best Practices\n\n### Design Principles\n\n1. **Keep middleware focused:** One concern per middleware\n2. **Handle errors gracefully:** Don't let middleware crash functions\n3. **Consider performance:** Middleware runs on every execution\n4. **Use proper typing:** Let TypeScript infer middleware types\n5. **Test thoroughly:** Middleware affects all functions that use it\n\n### Common Use Cases to Implement\n\n- **Retry logic** for transient failures\n- **Circuit breakers** for external service calls\n- **Request/response logging** for debugging\n- **User context enrichment** from external sources\n- **Feature flags** for gradual rollouts\n- **Custom authentication** and authorization checks\n\n### Error Handling in Middleware\n\n```typescript\nconst robustMiddleware = new InngestMiddleware({\n  name: \"Robust Middleware\",\n  init() {\n    return {\n      onFunctionRun({ ctx, fn }) {\n        return {\n          transformOutput({ result }) {\n            try {\n              // Your middleware logic here\n              return performTransformation(result);\n            } catch (middlewareError) {\n              // Log error but don't break the function\n              console.error(\"Middleware error:\", middlewareError);\n\n              // Return original result on middleware failure\n              return { result };\n            }\n          }\n        };\n      }\n    };\n  }\n});\n```\n\n### Testing Middleware\n\nUse Inngest's testing utilities (`createMockContext`, `createMockFunction`) to unit test middleware behavior.\n\n**For complete implementation examples and advanced patterns, see:**\n\n- [Dependency Injection Reference](./references/dependency-injection.md)\n- [Built-in Middleware Reference](./references/built-in-middleware.md)","tags":["inngest","middleware","skills","agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"capabilities":["skill","source-inngest","skill-inngest-middleware","topic-agent-skill-repository","topic-agent-skills","topic-agentic-skills","topic-ai-agents","topic-claude-code-skills","topic-cursor-skills","topic-openclaw-skills"],"categories":["inngest-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/inngest/inngest-skills/inngest-middleware","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add inngest/inngest-skills","source_repo":"https://github.com/inngest/inngest-skills","install_from":"skills.sh"}},"qualityScore":"0.458","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 17 github stars · SKILL.md body (9,161 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-23T01:02:09.175Z","embedding":null,"createdAt":"2026-04-18T23:06:58.210Z","updatedAt":"2026-04-23T01:02:09.175Z","lastSeenAt":"2026-04-23T01:02:09.175Z","tsv":"'-4':476 '/docs-markdown/reference/typescript/v4/migrations/v3-to-v4)':127 '/llms.txt)':87 '/references/built-in-middleware.md':506,876 '/references/dependency-injection.md':393,412,870 '0':485 '1':714 '1st':238 '2':722 '2nd':241 '3':732 '3rd':248 '4':740 '4th':251 '5':749 '8.0.0':600 'across':96,182,405 'add':172,583 'advanc':661,864 'affect':214,221,753 'afterexecut':329,634 'ai':451 'ai-summari':450 'alert':197 'allow':137 'api':116 'app':234,434,528,578 'appli':95,672 'array':374,377 'async':255,456 'authent':198,663,791 'authmiddlewar':246 'author':793 'automat':444,534 'avail':461 'await':467,477 'base':674,690 'bash':512,553 'basic':274 'beforeexecut':319,625 'behavior':858 'best':710 'beyond':489 'break':131,830 'breaker':681,770 'built':419,492,872 'built-in':418,491,871 'call':774 'captur':581 'cascad':683 'case':703,761 'catch':823 'chang':132 'check':794 'circuit':680,769 'client':147,180,212,260,294,404 'client-level':211 'code':138,257 'common':601,759 'complet':332,395,508,708,860 'concept':94 'concern':13,43,719 'condit':670 'config':570 'configur':689,696 'configuration-bas':688 'consid':733 'console.error':833 'const':227,282,296,427,465,521,571,609,635,648,800 'consult':121 'content':472 'context':201,464,597,669,780 'convert':372 'core':93 'count':364 'cover':14 'crash':730 'creat':4,18,271,692 'createmockcontext':852 'createmockfunct':853 'cross':11,41 'cross-cut':10,40 'ctx':316,619,810 'ctx.event.name':326,633,645 'ctx.runid':328,336 'custom':19,193,272,790 'cut':12,42 'data':51,184,190,482,538 'data.encrypted':543 'date.now':627,637 'db':440,459 'db.document.update':478 'debug':778 'depend':21,48,177,390,398,409,447,460,867 'dependencyinjectionmiddlewar':24,424,436,490 'design':712 'detail':129,414,509 'di':421 'differ':699 'document':84,111,706 'document/uploaded':455 'durat':636,641 'enabl':62 'encrypt':25,510,535 'encrypt/decrypt':186 'encryptionmiddlewar':518,530 'enrich':189,781 'environ':700 'error':29,46,191,194,551,651,724,795,826,835 'errormiddlewar':239 'event':153,253,354,363,366,454,457,542,594,632,644,676 'event.data.content':473 'event.data.documentid':481 'eventnam':325 'everi':738 'exampl':244,397,417,709,862 'except':582 'execut':152,165,224,301,739 'expens':401 'extern':686,772,783 'failur':684,768,842 'fallbackdecryptionkey':549 'featur':785 'field':544 'first':263 'flag':786 'fn':304,317,620,811 'fn.id':311,324,334,346,631,643,656 'focus':73,717 'follow':385 'function':60,69,151,183,216,219,223,256,265,300,321,331,340,343,407,443,463,539,587,591,630,642,655,679,731,755,832 'function-level':218 'functionid':323,333,345 'generic':310 'get':445 'go':79 'gpt':475 'grace':725 'gradual':788 'guid':124 'guidanc':92 'handl':39,192,723,796 'hook':110,161 'id':231,243,431,449,480,525,575,592 'implement':382,763,861 'import':278,423,517,558,563 'includ':590 'infer':746 'init':289,616,807 'initi':295 'inject':22,49,178,391,399,410,446,667,868 'inngest':2,7,33,36,83,146,164,228,230,281,426,428,430,496,522,524,572,574,848 'inngest-middlewar':1 'inngest.createfunction':242,448 'inngest.step.completed':654 'inngest.step.duration':640 'inngest.step.started':629 'inngest/middleware-encryption':27,515,520 'inngest/middleware-sentry':32,556,566 'inngestmiddlewar':279,285,612,803 'instal':514,555 'instanc':181 'keep':715 'key':56,531,533,546 'languag':90,98 'language-specif':89 'let':621,728,744 'level':213,220 'lifecycl':17,61,109,149,205,302,356 'like':44 'log':45,173,287,339,776,825 'logger':297 'logger.debug':342 'logger.info':320,330,361 'loggingmiddlewar':236,283 'logic':671,765,818 'loos':306 'master':35 'matter':259 'messag':469 'message.content':486 'metric':176,604,614 'metrics.histogram':639 'metrics.increment':628,653 'metricsmiddlewar':249,610 'middlewar':3,8,16,20,34,37,53,101,135,136,159,170,204,206,235,245,261,266,273,275,288,309,384,435,487,499,504,511,529,579,602,673,691,694,716,721,729,735,747,752,798,806,817,834,841,846,857,874 'middlewareerror':824,836 'migrat':118,123 'model':474 'mutabl':376 'my-app':232,432,526,576 'name':286,595,613,804 'new':229,284,429,438,441,523,573,611,802 'note':99,303 'npm':513,554 'number':623 'observ':66,171 'offici':498 'one':718 'onfunctionrun':315,618,809 'onsendev':357 'openai':437,439,458 'openai.chat.completions.create':468 'option':697 'order':225,258,269 'origin':838 'output':341,344,347,540 'p':368 'p.name':369 'packag':488,502 'pattern':64,388,415,603,662,865 'payload':360,379,380 'payloads.length':365 'payloads.map':367 'per':720 'perform':606,734 'performtransform':821 'permiss':203 'phase':291 'pipelin':166 'point':57,143 'power':63 'practic':711 'prevent':682 'principl':713 'prismacli':442 'process.env.encryption':532 'proper':742 'provid':497 'python':77,381,383,396 'quick':416 'readon':373 'refer':80,392,411,505,705,869,875 'reflect':113 'regist':209 'request/response':775 'requir':598 'result':338,351,353,647,660,814,822,839,844 'result.data':348 'result.error':650 'retri':764 'return':299,318,349,352,358,378,617,624,659,808,812,820,837,843 'reusabl':693 'rewritten':105 'robust':805 'robustmiddlewar':801 'role':470 'rollout':789 'rotat':547 'run':54,140,237,240,247,250,262,292,588,736 'runid':327,335 'runtim':314 'see':389,408,503,704,866 'send':154,355,362 'sentri':28,550,560,569,599 'sentry.init':567 'sentry/node':562 'sentrymiddlewar':564,580 'separ':501 'servic':687,773 'setup':290 'setuplogg':298 'share':68,179,400 'shown':494 'signific':104 'similar':387 'skill':71 'skill-inngest-middleware' 'sourc':784 'source-inngest' 'specif':91,222 'specifi':270 'spread':370 'start':322 'starttim':622,626,638 'state':403 'status':649,657,658 'step':537 'structur':276 'success':652 'summari':452,466,483 'summary.choices':484 'support':545 'system':102 'test':254,750,845,850,856 'think':157 'thorough':751 'token':665 'topic-agent-skill-repository' 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agents' 'topic-claude-code-skills' 'topic-cursor-skills' 'topic-openclaw-skills' 'trace':174,584 'track':30,47,195,552,607,615 'transform':52,185 'transforminput':359 'transformoutput':337,646,813 'transient':767 'tri':815 'trigger':252,453 'type':307,677,743,748 'typescript':75,226,277,422,516,557,608,745,799 'unit':855 'unmodifi':350 'use':6,169,702,741,757,760,847 'user':200,471,668,779 'util':851 'v3':120 'v4':107,115 'valid':187,199,664 'various':142 'via':26,31,548 'work':312 'www.inngest.com':86,126 'www.inngest.com/docs-markdown/reference/typescript/v4/migrations/v3-to-v4)':125 'www.inngest.com/llms.txt)':85","prices":[{"id":"fd32be34-9baa-4782-a1bc-fa3fcfeecc5a","listingId":"6e3d6c91-382b-4cdb-9bc3-bbc51e725d58","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"inngest","category":"inngest-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T23:06:58.210Z"}],"sources":[{"listingId":"6e3d6c91-382b-4cdb-9bc3-bbc51e725d58","source":"github","sourceId":"inngest/inngest-skills/inngest-middleware","sourceUrl":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-middleware","isPrimary":false,"firstSeenAt":"2026-04-18T23:06:58.210Z","lastSeenAt":"2026-04-23T01:02:09.175Z"}],"details":{"listingId":"6e3d6c91-382b-4cdb-9bc3-bbc51e725d58","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"inngest","slug":"inngest-middleware","github":{"repo":"inngest/inngest-skills","stars":17,"topics":["agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"license":"other","html_url":"https://github.com/inngest/inngest-skills","pushed_at":"2026-04-20T23:35:15Z","description":"Agent Skills for building with Inngest","skill_md_sha":"368a19fce279ae67039971ff88e6a040855387ec","skill_md_path":"skills/inngest-middleware/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-middleware"},"layout":"multi","source":"github","category":"inngest-skills","frontmatter":{"name":"inngest-middleware","description":"Create and use Inngest middleware for cross-cutting concerns. Covers the middleware lifecycle, creating custom middleware, dependency injection with dependencyInjectionMiddleware, encryption via @inngest/middleware-encryption, Sentry error tracking via @inngest/middleware-sentry, and custom middleware patterns."},"skills_sh_url":"https://skills.sh/inngest/inngest-skills/inngest-middleware"},"updatedAt":"2026-04-23T01:02:09.175Z"}}