Inngest is the durable execution engine for TypeScript. Write functions that survive crashes, retries, and timeouts — automatically.
Define Functions
import { Inngest } from "inngest";
const inngest = new Inngest({ id: "my-app" });
export const scrapeAndNotify = inngest.createFunction(
{ id: "scrape-and-notify", retries: 3 },
{ event: "scrape/requested" },
async ({ event, step }) => {
// Step 1: Scrape the URL (retried independently)
const data = await step.run("scrape-url", async () => {
const html = await fetch(event.data.url).then(r => r.text());
return parseProduct(html);
});
// Step 2: Save to database
const saved = await step.run("save-to-db", async () => {
return db.product.create({ data });
});
// Step 3: Send notification
await step.run("notify", async () => {
await sendEmail(event.data.email, {
subject: `Price update: ${data.title}`,
body: `New price: $${data.price}`,
});
});
return { product: saved };
}
);
If step 2 fails, step 1 is NOT re-run. Each step is memoized.
Events: Trigger From Anywhere
// From API route
app.post("/api/watch", async (req, res) => {
await inngest.send({
name: "scrape/requested",
data: { url: req.body.url, email: req.body.email },
});
res.json({ queued: true });
});
// Batch events
await inngest.send(
urls.map(url => ({ name: "scrape/requested", data: { url, email: "user@example.com" } }))
);
Scheduled Functions (Cron)
export const dailyPriceCheck = inngest.createFunction(
{ id: "daily-price-check" },
{ cron: "0 8 * * *" }, // 8 AM daily
async ({ step }) => {
const watchlist = await step.run("get-watchlist", () =>
db.watchlistItem.findMany({ where: { active: true } })
);
// Fan out: process each item
const results = await Promise.all(
watchlist.map(item =>
step.run(`check-${item.id}`, async () => {
const current = await scrapePrice(item.url);
if (current < item.targetPrice) {
await sendAlert(item.email, item.url, current);
return { alerted: true, price: current };
}
return { alerted: false, price: current };
})
)
);
return { checked: results.length, alerts: results.filter(r => r.alerted).length };
}
);
Wait for Events
export const orderWorkflow = inngest.createFunction(
{ id: "order-workflow" },
{ event: "order/created" },
async ({ event, step }) => {
await step.run("process-payment", () => chargeCard(event.data.orderId));
// Wait up to 7 days for shipment confirmation
const shipment = await step.waitForEvent("wait-for-shipment", {
event: "order/shipped",
match: "data.orderId",
timeout: "7d",
});
if (!shipment) {
await step.run("escalate", () => notifySupport(event.data.orderId));
}
}
);
Sleep: Delayed Execution
await step.sleep("wait-1-hour", "1h");
await step.sleepUntil("wait-until-morning", "2026-03-30T08:00:00Z");
Build durable scraping workflows? My Apify tools + Inngest = crash-proof data pipelines.
Custom workflow? Email spinov001@gmail.com
Top comments (0)