
Inngest Middleware
Wire Inngest client middleware for dependency injection, step/event encryption, and Sentry error reporting in serverless workflows.
Overview
inngest-middleware is an agent skill most often used in Build (also Ship security, Operate monitoring) that documents how to configure Inngest encryption, Sentry, and DI middleware with correct package imports.
Install
npx skills add https://github.com/inngest/inngest-skills --skill inngest-middlewareWhat is this skill?
- dependencyInjectionMiddleware exported from core inngest package
- encryptionMiddleware from @inngest/middleware-encryption—not core inngest
- sentryMiddleware from @inngest/middleware-sentry as separate package
- Default encrypts step data, function output, and event data.encrypted field
- Key rotation via fallbackDecryptionKeys and decryptOnly migration mode
- Encryption and Sentry middleware require two separate @inngest/middleware-* packages outside core inngest
Adoption & trust: 2.6k installs on skills.sh; 23 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You tried to import encryption or Sentry middleware from inngest and hit missing exports or wrong encryption fields on events.
Who is it for?
Indie SaaS backends using Inngest who need encrypted step data and Sentry in one reviewed setup.
Skip if: Projects not using Inngest, or teams that only need raw function handlers with zero middleware.
When should I use this skill?
You are configuring Inngest client middleware for encryption, Sentry, or dependency injection in TypeScript.
What do I get? / Deliverables
You install the right @inngest/middleware-* packages, configure keys and rotation, and attach middleware on the Inngest client constructor.
- Inngest client instantiation with ordered middleware array
- npm dependencies @inngest/middleware-encryption and/or @inngest/middleware-sentry as needed
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Middleware is configured when you implement the Inngest client and functions in your backend. Encryption and observability hooks live in the Node/TS Inngest app initialization layer alongside function definitions.
Where it fits
Bootstrap the Inngest client with encryptionMiddleware and DI before writing step functions.
Turn on full encryption and document eventEncryptionField before multi-tenant launch.
Add sentryMiddleware so failed steps surface in Sentry with correct package import.
How it compares
Inngest-specific middleware catalog, not generic Express middleware or AWS Lambda layers documentation.
Common Questions / FAQ
Who is inngest-middleware for?
Solo builders implementing Inngest in TypeScript who want encryption, Sentry, or dependency injection without guessing package boundaries.
When should I use inngest-middleware?
During Build backend when creating the Inngest client; at Ship security when enabling encryption before production traffic; at Operate monitoring when adding Sentry to background jobs.
Is inngest-middleware safe to install?
It is configuration guidance; review the Security Audits panel on this page and manage ENCRYPTION_KEY and Sentry DSN via your secret store.
SKILL.md
READMESKILL.md - Inngest Middleware
# Inngest Middleware Reference Inngest provides `dependencyInjectionMiddleware` as a built-in export from the `inngest` package. Encryption and Sentry middleware are available as **separate packages** that must be installed independently. > **Important:** `encryptionMiddleware` is from `@inngest/middleware-encryption` and `sentryMiddleware` is from `@inngest/middleware-sentry` — they are **not** exported from the core `inngest` package. ## Encryption Middleware (`@inngest/middleware-encryption`) Install the package: ```bash npm install @inngest/middleware-encryption ``` ```typescript import { Inngest } from "inngest"; import { encryptionMiddleware } from "@inngest/middleware-encryption"; const inngest = new Inngest({ id: "my-app", middleware: [ encryptionMiddleware({ key: process.env.ENCRYPTION_KEY, // Encryption key from environment }) ] }); ``` **What gets encrypted by default:** - All step data - All function output - Event data in the `data.encrypted` field (customizable via `eventEncryptionField`) **Additional options:** - `eventEncryptionField`: Customize which event data field to encrypt (default: `data.encrypted`) - `decryptOnly`: Disable encryption while maintaining decryption for migration scenarios - `fallbackDecryptionKeys`: Array of previous keys for key rotation support ```typescript // Key rotation example encryptionMiddleware({ key: process.env.NEW_ENCRYPTION_KEY, fallbackDecryptionKeys: [process.env.OLD_ENCRYPTION_KEY], }) ``` ### Custom Encryption Implementation For more control, create custom encryption middleware: ```typescript import { InngestMiddleware } from "inngest"; import { createCipher, createDecipher, randomBytes } from "crypto"; const createCustomEncryptionMiddleware = (encryptionKey: string) => { const algorithm = "aes-256-gcm"; const encrypt = (text: string): string => { const iv = randomBytes(16); const cipher = createCipher(algorithm, encryptionKey); cipher.setAAD(Buffer.from("inngest-data")); let encrypted = cipher.update(text, "utf8", "hex"); encrypted += cipher.final("hex"); const authTag = cipher.getAuthTag(); return iv.toString("hex") + ":" + authTag.toString("hex") + ":" + encrypted; }; const decrypt = (encrypted: string): string => { const [ivHex, authTagHex, encryptedText] = encrypted.split(":"); const iv = Buffer.from(ivHex, "hex"); const authTag = Buffer.from(authTagHex, "hex"); const decipher = createDecipher(algorithm, encryptionKey); decipher.setAAD(Buffer.from("inngest-data")); decipher.setAuthTag(authTag); let decrypted = decipher.update(encryptedText, "hex", "utf8"); decrypted += decipher.final("utf8"); return decrypted; }; return new InngestMiddleware({ name: "Custom Encryption", init() { return { onFunctionRun({ ctx }) { return { transformInput() { // Decrypt sensitive event data if (ctx.event.data.encrypted_fields) { const decryptedFields = {}; for (const [key, encryptedValue] of Object.entries( ctx.event.data.encrypted_fields )) { decryptedFields[key] = decrypt(encryptedValue as string); } return { ctx: { event: { ...ctx.event, data: { ...ctx.event.data, ...decryptedFields, encrypted_fields: undefined // Remove encrypted versions } } } }; } return {}; }, transformOutput({ result }) { // Encrypt sensitive output fields if (result.data?.sensitiveData) { const encrypted = encrypt( JSON.stringify(result.data.sensitiveData)