> inngest
You are an expert in Inngest, the event-driven durable workflow engine for TypeScript. You help developers build reliable multi-step workflows, scheduled jobs, and event-driven functions with automatic retries, step-level caching, fan-out/fan-in patterns, rate limiting, and debouncing — running on any serverless platform (Vercel, Netlify, AWS Lambda, Cloudflare) with zero infrastructure to manage.
curl "https://skillshub.wtf/TerminalSkills/skills/inngest?format=md"Inngest — Durable Workflow Engine for TypeScript
You are an expert in Inngest, the event-driven durable workflow engine for TypeScript. You help developers build reliable multi-step workflows, scheduled jobs, and event-driven functions with automatic retries, step-level caching, fan-out/fan-in patterns, rate limiting, and debouncing — running on any serverless platform (Vercel, Netlify, AWS Lambda, Cloudflare) with zero infrastructure to manage.
Core Capabilities
Functions and Steps
// inngest/functions/onboarding.ts
import { inngest } from "./client";
export const onboardUser = inngest.createFunction(
{
id: "onboard-user",
retries: 3,
concurrency: [{ limit: 10 }], // Max 10 concurrent executions
},
{ event: "user/signed-up" },
async ({ event, step }) => {
// Step 1: Create account (cached — won't re-run on retry)
const user = await step.run("create-account", async () => {
return await db.users.create({
email: event.data.email,
name: event.data.name,
});
});
// Step 2: Send welcome email
await step.run("send-welcome", async () => {
await resend.emails.send({
to: user.email,
subject: "Welcome!",
react: WelcomeEmail({ name: user.name }),
});
});
// Step 3: Wait 24 hours (durable — survives deployments)
await step.sleep("wait-for-activation", "24 hours");
// Step 4: Check if user activated
const activated = await step.run("check-activation", async () => {
const u = await db.users.findById(user.id);
return u.activatedAt !== null;
});
if (!activated) {
// Step 5: Send reminder
await step.run("send-reminder", async () => {
await resend.emails.send({
to: user.email,
subject: "Complete your setup",
react: ReminderEmail({ name: user.name }),
});
});
}
return { userId: user.id, activated };
},
);
// Fan-out: process items in parallel
export const processBatch = inngest.createFunction(
{ id: "process-batch" },
{ event: "batch/uploaded" },
async ({ event, step }) => {
const items = event.data.items;
// Fan-out — run up to 10 items in parallel
const results = await Promise.all(
items.map((item, i) =>
step.run(`process-item-${i}`, () => processItem(item))
),
);
// Fan-in — aggregate results
const summary = await step.run("summarize", () => ({
total: results.length,
success: results.filter(r => r.status === "ok").length,
failed: results.filter(r => r.status === "error").length,
}));
return summary;
},
);
// Scheduled (cron)
export const dailyCleanup = inngest.createFunction(
{ id: "daily-cleanup" },
{ cron: "0 3 * * *" }, // 3 AM daily
async ({ step }) => {
const deleted = await step.run("cleanup-expired", async () => {
return await db.sessions.deleteWhere({ expiresAt: { lt: new Date() } });
});
return { deletedSessions: deleted };
},
);
Event-Driven
// Send events from anywhere
import { inngest } from "./client";
// From API route
app.post("/api/signup", async (req, res) => {
const user = await createUser(req.body);
await inngest.send({
name: "user/signed-up",
data: { email: user.email, name: user.name, userId: user.id },
});
res.json(user);
});
// Batch events
await inngest.send([
{ name: "order/created", data: { orderId: "1" } },
{ name: "order/created", data: { orderId: "2" } },
]);
Debounce and Rate Limit
export const syncCRM = inngest.createFunction(
{
id: "sync-crm",
debounce: { period: "5m", key: "event.data.userId" }, // Wait 5min, take latest
rateLimit: { limit: 100, period: "1h" }, // Max 100/hour
},
{ event: "user/updated" },
async ({ event, step }) => {
await step.run("sync", () => crm.upsertContact(event.data));
},
);
Installation
npx inngest-cli@latest init
npx inngest-cli@latest dev # Local dev server with UI
Best Practices
- Steps are checkpoints — Each
step.run()is cached; if the function retries, completed steps are skipped - step.sleep for delays — Durable sleep survives deployments and restarts; use for drip campaigns, reminders
- Fan-out with step.run — Use
Promise.allwith indexed step names for parallel processing - Debounce for noisy events — Use debounce for events that fire rapidly (user edits, webhook storms)
- Rate limiting — Protect downstream APIs with built-in rate limits; no external tools needed
- Event-first architecture — Send events from your app; Inngest triggers functions automatically
- Local dev UI — Run
inngest devfor a visual dashboard showing function runs, events, and step details - Zero infrastructure — Works on any serverless platform; Inngest handles queuing, retries, scheduling
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.