What is Inngest?
Inngest is a developer-first, event-driven background job platform that enables building durable, serverless workflows using plain JavaScript/TypeScript functions. It provides powerful primitives like retries, delays, branching logic, and observability—without needing to manage infrastructure or complex orchestration systems.
⚙️Core Concepts
Events
Events are payloads that describe something that happened (e.g. user.signed_up, order.completed).
They are the triggers for Inngest functions.
{
"name": "user.signed_up",
"data": {
"userId": "abc123",
"email": "angel@example.com"
}
}
Functions
Functions are units of work that respond to specific events.
Functions can contain multiple steps (via step.run) and are durable—they persist state across failures and can resume on retry.
export const sendWelcomeEmail = inngest.createFunction(
{ id: "welcome-email" },
{ event: "user.signed_up" },
async ({ event, step }) => {
await step.run("send email", async () => {
await emailClient.sendWelcome(event.data.email);
});
}
);
Steps
Steps are atomic operations within a function.
Each step:
- Is automatically retried on failure.
- Persists its result (won’t re-run unless logic changes).
- Can be delayed or run conditionally.
await step.sleep("wait 2 minutes", "2m"); // Delay
Serve
You expose your Inngest functions through a server (Next.js, Express, etc.) so Inngest can call them.
// Next.js
export default serve(inngest, [sendWelcomeEmail, ...moreFunctions]);
Architecture Overview
[ App/API ] --> emits events
\
--> [ Inngest Platform ] -- invokes --> [ Inngest Functions (hosted in your app) ]
↳ with retry, steps, observability, etc.
Typical Use Cases
Use Case | Event | Function Descriptiion |
---|---|---|
Welcome Email | user.signed_up |
Sends email and tracks signup source |
Order Processing | order.placed |
Orchestrates billing, stock check, and fulfillment |
Retry Failed Webhooks | webhook.failed |
Re-attempts delivery using exponential backoff |
Scheduled Reports | daily.report.ready |
Sends Slack summary of daily data |
Wait-based Workflows | payment.initiated |
Wait 1hr, then confirm payment |
Local Development Workflow
Install CLI
npm install -g inngest-cli
Start Dev Server
inngest dev
- Watches your functions
- Starts a local UI on http://localhost:8288
- Proxies events to your local API (e.g. /api/inngest)
Send Events for Testing
inngest send --name user.signed_up --data '{"email": "test@site.com"}'
Or use the Inngest Dev UI to manually craft and send events.
Advanced Function Capabilities
Step Dependencies and Branching
await step.run("check account", async () => {
const account = await db.getAccount(event.data.userId);
if (!account.isActive) throw new Error("Inactive user");
});
Parallel Execution
const [emailResult, analyticsResult] = await Promise.all([
step.run("send email", sendEmail),
step.run("track analytics", trackAnalytics)
]);
Conditional Steps
if (event.data.plan === "premium") {
await step.run("provision premium", provisionPremiumFeatures);
}
Scheduling / Delays
await step.sleep("wait 24 hours", "24h");
await step.run("send reminder", sendReminderEmail);
Integration Patterns
From Backend Services
await inngest.send({
name: "user.signed_up",
data: { userId: "123", email: "test@example.com" }
});
From Frontend (via REST Proxy)
Create an API route to relay frontend events to Inngest.
// POST /api/events
const { name, data } = req.body;
await inngest.send({ name, data });
Error Handling & Observability
- Each step is retried automatically on failure (configurable).
- Function logs and run history are visible in the Inngest UI.
- Use console.log() inside functions to view logs in real time.
- Catch and throw specific errors to control retry behavior.
throw new InngestError("Custom failure", { retry: false });
☁️ Deployment Tips
- In Next.js, deploy your API route (/api/inngest) to platforms like Vercel or AWS Lambda.
- Functions are invoked over HTTP by the Inngest platform—no need to keep them always running.
- Separate dev/staging/prod apps in the Inngest dashboard to isolate events.
🛠 Best Practices
- Use clear event naming: object.action (e.g. user.created, checkout.completed)
- Use step names that describe the action clearly for observability.
- Treat steps like checkpoints: return useful data and avoid side-effects in raw function body.
- Keep functions single-purpose—break out business logic into utilities where possible.
- Enable function versioning via unique IDs or suffixes to maintain traceability.
Top comments (0)