inngest-steps
Use when implementing delays that must survive process restarts (e.g., 24-hour cart abandonment, scheduled follow-ups), waiting for human approval or external events with timeouts (review gates, webhook callbacks, async API completion), polling external services without losing state on crashes, call
By inngest · 3,444 installs
npx skills add inngest/inngest-skills --skill inngest-steps
Source repository · Upstream listing
Inngest Steps
Build robust, durable workflows with Inngest's step methods. Each step is a separate HTTP request that can be independently retried and monitored.
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.
Core Concept
🔄 Critical: Each step re runs your function from the beginning. Put ALL non deterministic code (API calls, DB queries, randomness) inside steps, never outside.
📊 Step Limits: Every function has a maximum of 1,000 steps and 4MB total step data.
step.run()
Execute retriable code as a step. Each step ID can be reused Inngest automatically handles counters.
✅ DO:
Put ALL non deterministic logic inside steps
Return useful data for subsequent steps
Reuse step IDs in loops (counters handled automatically)
❌ DON'T:
Put deterministic logic in steps unnecessarily
Forget that each step = separate HTTP request
step.sleep()
Pause execution without using compute time.
step.sleepUntil()
Sleep until a specific datetime.
step.waitForEvent()
🚨 CRITICAL: waitForEvent ONLY catches events sent AFTER this step executes.
❌ Event sent before waitForEvent runs → will NOT be caught
✅ Event sent after waitForEvent runs → will be caught
Always check for null return (means timeout, event never arrived)
✅ DO:
Use unique IDs for matching (userId, sessionId, requestId)
Always set reasonable timeouts
Handle null return (timeout case)
Use with Realtime for human in the loop flows
❌ DON'T:
Expect events sent before this step to be handled
Use without timeouts in production
Expression Syntax
In expressions, event = the original triggering event, async = the new event being matched. See [Expression Syntax Reference](../references/expressions.md) for full syntax, operators, and patterns.
step.waitForSignal()
Wait for unique signals (not events). Better for 1:1 matching.
When to use:
waitForEvent : Multiple functions might handle the same event
waitForSignal : Exact 1:1 signal to specific function run
step.sendEvent()
Fan out to other functions without waiting for results.
Use when: You want to trigger other functions but don't need their results in the current function.
step.invoke()
Call other functions and handle their results. Perfect for composition.
Warning: v4 Breaking Change: String function IDs (e.g., function: "my app other fn" ) are no longer supported in step.invoke() . Use an imported function reference or referenceFunction() for cross app calls.
Great for:
Breaking complex workflows into composable functions
Reusing logic across multiple workflows
Map reduce patterns
Patterns
Loops with Steps
Reuse step IDs Inngest handles counters automatically.
Parallel Execution
Use Promise.all for parallel steps. In v4, parallel step execution is optimized by default
See inngest flow control for concurrency and throttling options.
Chunking Jobs
Perfect for batch processing with parallel steps.
Key Gotchas
🔄 Function Re execution: Code outside steps runs on every step execution
⏰ Event Timing: waitForEvent only catches events sent AFTER the step runs
🔢 Step Limits: Max 1,000 steps per function, 4MB per step output, 32MB per function run in total
📨 HTTP Requests: Checkpointing is enabled by default in v4, reducing HTTP overhead. For serverless platforms, configure maxRuntime on the client
🔁 Step IDs: Can be reused in loops Inngest handles counters
⚡ Parallelism: Use Promise.all for parallel steps (optimized by default in v4). Note that Promise.race() waits for all promises to settle — use group.parallel() for true race semantics
Common Use Cases
Human in the loop: waitForEvent + Realtime UI
Multi step onboarding: sleep between steps, waitForEvent for user actions
Data processing: Parallel steps for chunked work
External integrations: step.run for reliable API calls
AI workflows: step.ai for durable LLM orchestration
Function composition: step.invoke to build complex workflows
Remember: Steps make your functions durable, observable, and debuggable. Embrace them!