{"id":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","shortId":"ctLnXc","kind":"skill","title":"inngest-durable-functions","tagline":"Use when building functions that must survive process crashes, retry automatically on failure, run on a schedule, react to events, or maintain state across infrastructure failures — e.g., webhook handlers that drop events, flaky cron jobs, background jobs that fail mid-execution,","description":"# Inngest Durable Functions\n\nMaster Inngest's durable execution model for building fault-tolerant, long-running workflows. This skill covers the complete lifecycle from triggers to error handling.\n\n> **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.\n\n## Core Concepts You Need to Know\n\n### **Durable Execution Model**\n\n- **Each step** should encapsulate side-effects and non-deterministic code\n- **Memoization** prevents re-execution of completed steps\n- **State persistence** survives infrastructure failures\n- **Automatic retries** with configurable retry count\n\n### **Step Execution Flow**\n\n```typescript\n// ❌ BAD: Non-deterministic logic outside steps\nasync ({ event, step }) => {\n  const timestamp = Date.now(); // This runs multiple times!\n\n  const result = await step.run(\"process-data\", () => {\n    return processData(event.data);\n  });\n};\n\n// ✅ GOOD: All non-deterministic logic in steps\nasync ({ event, step }) => {\n  const result = await step.run(\"process-with-timestamp\", () => {\n    const timestamp = Date.now(); // Only runs once\n    return processData(event.data, timestamp);\n  });\n};\n```\n\n## Function Limits\n\n**Every Inngest function has these hard limits:**\n\n- **Maximum 1,000 steps** per function run\n- **Maximum 4MB** returned data for each step\n- **Maximum 32MB** combined function run state including, event data, step output, and function output\n- Each step = separate HTTP request (~50-100ms overhead)\n\nIf you're hitting these limits, break your function into smaller functions connected via `step.invoke()` or `step.sendEvent()`.\n\n## When to Use Steps\n\n**Always wrap in `step.run()`:**\n\n- API calls and network requests\n- Database reads and writes\n- File I/O operations\n- Any non-deterministic operation\n- Anything you want retried independently on failure\n\n**Never wrap in `step.run()`:**\n\n- Pure calculations and data transformations\n- Simple validation logic\n- Deterministic operations with no side effects\n- Logging (use outside steps)\n\n## Function Creation\n\n### Basic Function Structure\n\n```typescript\nconst processOrder = inngest.createFunction(\n  {\n    id: \"process-order\", // Unique, never change this\n    triggers: [{ event: \"order/created\" }],\n    retries: 4, // Default: 4 retries per step\n    concurrency: 10 // Max concurrent executions\n  },\n  async ({ event, step }) => {\n    // Your durable workflow\n  }\n);\n```\n\n### **Step IDs and Memoization**\n\n```typescript\n// Step IDs can be reused - Inngest handles counters automatically\nconst data = await step.run(\"fetch-data\", () => fetchUserData());\nconst more = await step.run(\"fetch-data\", () => fetchOrderData()); // Different execution\n\n// Use descriptive IDs for clarity\nawait step.run(\"validate-payment\", () => validatePayment(event.data.paymentId));\nawait step.run(\"charge-customer\", () => chargeCustomer(event.data));\nawait step.run(\"send-confirmation\", () => sendEmail(event.data.email));\n```\n\n## Triggers and Events\n\n### **Event Triggers**\n\nTriggers are defined in the `triggers` array in the first argument of `createFunction`:\n\n```typescript\n// Single event trigger\ninngest.createFunction(\n  { id: \"my-fn\", triggers: [{ event: \"user/signup\" }] },\n  async ({ event }) => { /* ... */ }\n);\n\n// Event with conditional filter\ninngest.createFunction(\n  { id: \"my-fn\", triggers: [{ event: \"user/action\", if: 'event.data.action == \"purchase\" && event.data.amount > 100' }] },\n  async ({ event }) => { /* ... */ }\n);\n\n// Multiple triggers (up to 10)\ninngest.createFunction(\n  {\n    id: \"my-fn\",\n    triggers: [\n      { event: \"user/signup\" },\n      { event: \"user/login\", if: 'event.data.firstLogin == true' },\n      { cron: \"0 9 * * *\" } // Daily at 9 AM\n    ]\n  },\n  async ({ event }) => { /* ... */ }\n);\n```\n\n### **Cron Triggers**\n\n```typescript\n// Basic cron\ninngest.createFunction(\n  { id: \"my-fn\", triggers: [{ cron: \"0 */6 * * *\" }] }, // Every 6 hours\n  async ({ step }) => { /* ... */ }\n);\n\n// With timezone\ninngest.createFunction(\n  { id: \"my-fn\", triggers: [{ cron: \"TZ=Europe/Paris 0 12 * * 5\" }] }, // Fridays at noon Paris time\n  async ({ step }) => { /* ... */ }\n);\n\n// Combine with events\ninngest.createFunction(\n  {\n    id: \"my-fn\",\n    triggers: [\n      { event: \"manual/report.requested\" },\n      { cron: \"0 0 * * 0\" } // Weekly on Sunday\n    ]\n  },\n  async ({ event, step }) => { /* ... */ }\n);\n```\n\n### **Function Invocation**\n\n```typescript\n// Invoke another function as a step\nconst result = await step.invoke(\"generate-report\", {\n  function: generateReportFunction,\n  data: { userId: event.data.userId }\n});\n\n// Use returned data\nawait step.run(\"process-report\", () => {\n  return processReport(result);\n});\n```\n\n## Idempotency Strategies\n\n### **Event-Level Idempotency (Producer Side)**\n\n```typescript\n// Prevent duplicate events with custom ID\nawait inngest.send({\n  id: `checkout-completed-${cartId}`, // 24-hour deduplication\n  name: \"cart/checkout.completed\",\n  data: { cartId, email: \"user@example.com\" }\n});\n```\n\n### **Function-Level Idempotency (Consumer Side)**\n\n```typescript\nconst sendEmail = inngest.createFunction(\n  {\n    id: \"send-checkout-email\",\n    triggers: [{ event: \"cart/checkout.completed\" }],\n    // Only run once per cartId per 24 hours\n    idempotency: \"event.data.cartId\"\n  },\n  async ({ event, step }) => {\n    // This function won't run twice for same cartId\n  }\n);\n\n// Complex idempotency keys\nconst processUserAction = inngest.createFunction(\n  {\n    id: \"process-user-action\",\n    triggers: [{ event: \"user/action.performed\" }],\n    // Unique per user + organization combination\n    idempotency: 'event.data.userId + \"-\" + event.data.organizationId'\n  },\n  async ({ event, step }) => {\n    /* ... */\n  }\n);\n```\n\n## Cancellation Patterns\n\n### **Event-Based Cancellation**\n\nIn expressions, `event` = the **original** triggering event, `async` = the **new** event being matched. See [Expression Syntax Reference](../references/expressions.md) for full details.\n\n```typescript\nconst processOrder = inngest.createFunction(\n  {\n    id: \"process-order\",\n    triggers: [{ event: \"order/created\" }],\n    cancelOn: [\n      {\n        event: \"order/cancelled\",\n        if: \"event.data.orderId == async.data.orderId\"\n      }\n    ]\n  },\n  async ({ event, step }) => {\n    await step.sleepUntil(\"wait-for-payment\", event.data.paymentDue);\n    // Will be cancelled if order/cancelled event received\n    await step.run(\"charge-payment\", () => processPayment(event.data));\n  }\n);\n```\n\n### **Timeout Cancellation**\n\n```typescript\nconst processWithTimeout = inngest.createFunction(\n  {\n    id: \"process-with-timeout\",\n    triggers: [{ event: \"long/process.requested\" }],\n    timeouts: {\n      start: \"5m\", // Cancel if not started within 5 minutes\n      finish: \"30m\" // Cancel if not finished within 30 minutes\n    }\n  },\n  async ({ event, step }) => {\n    /* ... */\n  }\n);\n```\n\n### **Handling Cancellation Cleanup**\n\n```typescript\n// Listen for cancellation events\nconst cleanupCancelled = inngest.createFunction(\n  { id: \"cleanup-cancelled-process\", triggers: [{ event: \"inngest/function.cancelled\" }] },\n  async ({ event, step }) => {\n    if (event.data.function_id === \"process-order\") {\n      await step.run(\"cleanup-resources\", () => {\n        return cleanupOrderResources(event.data.run_id);\n      });\n    }\n  }\n);\n```\n\n## Error Handling and Retries\n\n### **Default Retry Behavior**\n\n- **5 total attempts** (1 initial + 4 retries) per step\n- **Exponential backoff** with jitter\n- **Independent retry counters** per step\n\n### **Custom Retry Configuration**\n\n```typescript\nconst reliableFunction = inngest.createFunction(\n  {\n    id: \"reliable-function\",\n    triggers: [{ event: \"critical/task\" }],\n    retries: 10 // Up to 10 retries per step\n  },\n  async ({ event, step, attempt }) => {\n    // `attempt` is the function-level attempt counter (0-indexed)\n    // It tracks retries for the currently executing step, not the overall function\n    if (attempt > 5) {\n      // Different logic for later attempts of the current step\n    }\n  }\n);\n```\n\n### **Non-Retriable Errors**\n\nPrevent retries for code that won't succeed upon retry.\n\n```typescript\nimport { NonRetriableError } from \"inngest\";\n\nconst processUser = inngest.createFunction(\n  { id: \"process-user\", triggers: [{ event: \"user/process.requested\" }] },\n  async ({ event, step }) => {\n    const user = await step.run(\"fetch-user\", async () => {\n      const user = await db.users.findOne(event.data.userId);\n\n      if (!user) {\n        // Don't retry - user doesn't exist\n        throw new NonRetriableError(\"User not found, stopping execution\");\n      }\n\n      return user;\n    });\n\n    // Continue processing...\n  }\n);\n```\n\n### **Custom Retry Timing**\n\n```typescript\nimport { RetryAfterError } from \"inngest\";\n\nconst respectRateLimit = inngest.createFunction(\n  { id: \"api-call\", triggers: [{ event: \"api/call.requested\" }] },\n  async ({ event, step }) => {\n    await step.run(\"call-api\", async () => {\n      const response = await externalAPI.call(event.data);\n\n      if (response.status === 429) {\n        // Retry after specific time from API\n        const retryAfter = response.headers[\"retry-after\"];\n        throw new RetryAfterError(\"Rate limited\", `${retryAfter}s`);\n      }\n\n      return response.data;\n    });\n  }\n);\n```\n\n## Logging Best Practices\n\n### **Proper Logging Setup**\n\n```typescript\nimport winston from \"winston\";\n\n// Configure logger\nconst logger = winston.createLogger({\n  level: \"info\",\n  format: winston.format.json(),\n  transports: [new winston.transports.Console()]\n});\n\nconst inngest = new Inngest({\n  id: \"my-app\",\n  logger // Pass logger to client\n});\n\n// Or use the built-in ConsoleLogger for simple log level control\nimport { ConsoleLogger, Inngest } from \"inngest\";\n\nconst inngest = new Inngest({\n  id: \"my-app\",\n  logger: new ConsoleLogger({ level: \"debug\" }) // \"debug\" | \"info\" | \"warn\" | \"error\"\n});\n```\n\n**⚠️ v4 Breaking Change:** The `logLevel` option has been removed. Use the `logger` option with `ConsoleLogger` or a custom logger instead.\n\n### **Function Logging Patterns**\n\n```typescript\nconst processData = inngest.createFunction(\n  { id: \"process-data\", triggers: [{ event: \"data/process.requested\" }] },\n  async ({ event, step, logger }) => {\n    // ✅ GOOD: Log inside steps to avoid duplicates\n    const result = await step.run(\"fetch-data\", async () => {\n      logger.info(\"Fetching data for user\", { userId: event.data.userId });\n      return await fetchUserData(event.data.userId);\n    });\n\n    // ❌ AVOID: Logging outside steps can duplicate\n    // logger.info(\"Processing complete\"); // This could run multiple times!\n\n    await step.run(\"log-completion\", async () => {\n      logger.info(\"Processing complete\", { resultCount: result.length });\n    });\n  }\n);\n```\n\n## Performance Optimization\n\n### **Checkpointing**\n\nCheckpointing is **enabled by default in v4**. It allows functions to persist state periodically during execution, reducing latency between steps.\n\n```typescript\n// Checkpointing is enabled by default in v4\n// Configure maxRuntime for serverless platforms (set to 60-80% of platform timeout)\nconst realTimeFunction = inngest.createFunction(\n  {\n    id: \"real-time-function\",\n    triggers: [{ event: \"realtime/process\" }],\n    checkpointing: {\n      maxRuntime: \"50s\", // For serverless with 60s timeout\n    }\n  },\n  async ({ event, step }) => {\n    // Steps execute immediately with periodic checkpointing\n    const result1 = await step.run(\"step-1\", () => process1(event.data));\n    const result2 = await step.run(\"step-2\", () => process2(result1));\n    return { result2 };\n  }\n);\n\n// Disable checkpointing if needed\nconst legacyFunction = inngest.createFunction(\n  {\n    id: \"legacy-function\",\n    triggers: [{ event: \"legacy/process\" }],\n    checkpointing: false\n  },\n  async ({ event, step }) => { /* ... */ }\n);\n```\n\n## Advanced Patterns\n\n### **Conditional Step Execution**\n\n```typescript\nconst conditionalProcess = inngest.createFunction(\n  { id: \"conditional-process\", triggers: [{ event: \"process/conditional\" }] },\n  async ({ event, step }) => {\n    const userData = await step.run(\"fetch-user\", () => {\n      return getUserData(event.data.userId);\n    });\n\n    // Conditional step execution\n    if (userData.isPremium) {\n      await step.run(\"premium-processing\", () => {\n        return processPremiumFeatures(userData);\n      });\n    }\n\n    // Always runs\n    await step.run(\"standard-processing\", () => {\n      return processStandardFeatures(userData);\n    });\n  }\n);\n```\n\n### **Error Recovery Patterns**\n\n```typescript\nconst robustProcess = inngest.createFunction(\n  { id: \"robust-process\", triggers: [{ event: \"process/robust\" }] },\n  async ({ event, step }) => {\n    let primaryResult;\n\n    try {\n      primaryResult = await step.run(\"primary-service\", () => {\n        return callPrimaryService(event.data);\n      });\n    } catch (error) {\n      // Fallback to secondary service\n      primaryResult = await step.run(\"fallback-service\", () => {\n        return callSecondaryService(event.data);\n      });\n    }\n\n    return { result: primaryResult };\n  }\n);\n```\n\n## Common Mistakes to Avoid\n\n1. **❌ Non-deterministic code outside steps**\n2. **❌ Database calls outside steps**\n3. **❌ Logging outside steps (causes duplicates)**\n4. **❌ Changing step IDs after deployment**\n5. **❌ Not handling NonRetriableError cases**\n6. **❌ Ignoring idempotency for critical functions**\n\n## Next Steps\n\n- See **inngest-steps** for detailed step method reference\n- See [references/step-execution.md](references/step-execution.md) for detailed step patterns\n- See [references/error-handling.md](references/error-handling.md) for comprehensive error strategies\n- See [references/observability.md](references/observability.md) for monitoring and tracing setup\n- See [references/checkpointing.md](references/checkpointing.md) for performance optimization details\n\n---\n\n_This skill covers Inngest's durable function patterns. For event sending and webhook handling, see the `inngest-events` skill._","tags":["inngest","durable","functions","skills","agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"capabilities":["skill","source-inngest","skill-inngest-durable-functions","topic-agent-skill-repository","topic-agent-skills","topic-agentic-skills","topic-ai-agents","topic-claude-code-skills","topic-cursor-skills","topic-openclaw-skills"],"categories":["inngest-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/inngest/inngest-skills/inngest-durable-functions","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add inngest/inngest-skills","source_repo":"https://github.com/inngest/inngest-skills","install_from":"skills.sh"}},"qualityScore":"0.461","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 22 github stars · SKILL.md body (14,095 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:05:31.101Z","embedding":null,"createdAt":"2026-04-18T23:06:55.839Z","updatedAt":"2026-05-18T19:05:31.101Z","lastSeenAt":"2026-05-18T19:05:31.101Z","tsv":"'-1':1268 '-100':248 '-2':1276 '-80':1231 '/6':509 '/llms.txt)':93 '/references/expressions.md':708 '0':488,508,526,548,549,550,885 '000':216 '1':215,836,1403 '10':350,473,866,869 '100':466 '12':527 '2':1410 '24':611,644 '3':1415 '30':784 '30m':778 '32mb':229 '4':343,345,838,1421 '429':1011 '4mb':222 '5':528,775,833,901,1427 '50':247 '50s':1248 '5m':769 '6':511,1432 '60':1230 '60s':1252 '9':489,492 'across':28,102 'action':670 'advanc':1300 'allow':1203 'alway':272,1342 'anoth':561 'anyth':293 'api':276,990,1002,1017 'api-cal':989 'api/call.requested':994 'app':1063,1093 'appli':101 'argument':433 'array':429 'async':156,184,354,448,467,494,513,534,554,648,682,698,729,786,808,873,940,950,995,1003,1137,1155,1186,1254,1297,1316,1366 'async.data.orderid':728 'attempt':835,876,877,883,900,906 'automat':15,139,373 'avoid':1146,1167,1402 'await':168,189,376,384,397,404,411,568,581,604,732,746,817,945,953,998,1006,1150,1164,1181,1265,1273,1321,1334,1344,1373,1388 'background':40 'backoff':843 'bad':149 'base':689 'basic':324,499 'behavior':832 'best':1034 'break':257,1104 'build':7,57 'built':1073 'built-in':1072 'calcul':305 'call':277,991,1001,1412 'call-api':1000 'callprimaryservic':1379 'callsecondaryservic':1394 'cancel':685,690,741,754,770,779,790,795,803 'cancelon':723 'cart/checkout.completed':615,637 'cartid':610,617,642,659 'case':1431 'catch':1381 'caus':1419 'chang':337,1105,1422 'charg':407,749 'charge-custom':406 'charge-pay':748 'chargecustom':409 'checkout':608,633 'checkout-complet':607 'checkpoint':1194,1195,1216,1246,1262,1282,1295 'clariti':396 'cleanup':791,802,820 'cleanup-cancelled-process':801 'cleanup-resourc':819 'cleanupcancel':798 'cleanuporderresourc':823 'client':1068 'code':125,918,1407 'combin':230,536,678 'common':1399 'complet':69,132,609,1175,1185,1189 'complex':660 'comprehens':1460 'concept':100,106 'concurr':349,352 'condit':452,1302,1311,1329 'conditional-process':1310 'conditionalprocess':1307 'configur':142,853,1044,1223 'confirm':415 'connect':263 'consolelogg':1075,1082,1096,1117 'const':159,166,187,195,328,374,382,566,627,663,713,756,797,855,930,943,951,985,1004,1018,1046,1056,1086,1127,1148,1235,1263,1271,1285,1306,1319,1356 'consum':624 'continu':975 'control':1080 'core':99,105 'could':1177 'count':144 'counter':372,848,884 'cover':67,1480 'crash':13 'createfunct':435 'creation':323 'critic':1436 'critical/task':864 'cron':38,487,496,500,507,523,547 'current':892,909 'custom':408,602,851,977,1120 'daili':490 'data':172,224,236,307,375,380,388,575,580,616,1133,1154,1158 'data/process.requested':1136 'databas':281,1411 'date.now':161,197 'db.users.findone':954 'debug':1098,1099 'dedupl':613 'default':344,830,1199,1220 'defin':425 'deploy':1426 'descript':393 'detail':711,1445,1453,1477 'determinist':124,152,180,291,312,1406 'differ':390,902 'disabl':1281 'document':90 'doesn':962 'drop':35 'duplic':599,1147,1172,1420 'durabl':3,48,53,111,358,1483 'e.g':31 'effect':120,317 'email':618,634 'enabl':1197,1218 'encapsul':117 'error':74,826,914,1102,1352,1382,1461 'europe/paris':525 'event':24,36,157,185,235,340,355,420,421,438,446,449,450,460,468,480,482,495,538,545,555,592,600,636,649,672,683,688,693,697,701,721,724,730,744,765,787,796,806,809,863,874,938,941,993,996,1135,1138,1244,1255,1293,1298,1314,1317,1364,1367,1487,1496 'event-bas':687 'event-level':591 'event.data':175,203,410,752,1008,1270,1380,1395 'event.data.action':463 'event.data.amount':465 'event.data.cartid':647 'event.data.email':417 'event.data.firstlogin':485 'event.data.function':812 'event.data.orderid':727 'event.data.organizationid':681 'event.data.paymentdue':738 'event.data.paymentid':403 'event.data.run':824 'event.data.userid':577,680,955,1162,1166,1328 'everi':207,510 'execut':46,54,112,130,146,353,391,893,972,1210,1258,1304,1331 'exist':964 'exponenti':842 'express':692,705 'externalapi.call':1007 'fail':43 'failur':17,30,138,299 'fallback':1383,1391 'fallback-servic':1390 'fals':1296 'fault':59 'fault-toler':58 'fetch':379,387,948,1153,1157,1324 'fetch-data':378,386,1152 'fetch-us':947,1323 'fetchorderdata':389 'fetchuserdata':381,1165 'file':285 'filter':453 'finish':777,782 'first':432 'flaki':37 'flow':147 'fn':444,458,478,505,521,543 'focus':79 'format':1051 'found':970 'friday':529 'full':710 'function':4,8,49,205,209,219,231,240,259,262,322,325,557,562,573,621,652,861,881,898,1123,1204,1242,1291,1437,1484 'function-level':620,880 'generat':571 'generate-report':570 'generatereportfunct':574 'getuserdata':1327 'go':85 'good':176,1141 'guidanc':98 'handl':75,371,789,827,1429,1491 'handler':33 'hard':212 'hit':254 'hour':512,612,645 'http':245 'i/o':286 'id':331,361,366,394,441,455,475,502,518,540,603,606,630,666,716,759,800,813,825,858,933,988,1060,1090,1130,1238,1288,1309,1359,1424 'idempot':589,594,623,646,661,679,1434 'ignor':1433 'immedi':1259 'import':926,981,1040,1081 'includ':234 'independ':297,846 'index':886 'info':1050,1100 'infrastructur':29,137 'initi':837 'inngest':2,47,51,89,208,370,929,984,1057,1059,1083,1085,1087,1089,1442,1481,1495 'inngest-durable-funct':1 'inngest-ev':1494 'inngest-step':1441 'inngest.createfunction':330,440,454,474,501,517,539,629,665,715,758,799,857,932,987,1129,1237,1287,1308,1358 'inngest.send':605 'inngest/function.cancelled':807 'insid':1143 'instead':1122 'invoc':558 'invok':560 'jitter':845 'job':39,41 'key':662 'know':110 'languag':96,104 'language-specif':95 'latenc':1212 'later':905 'legaci':1290 'legacy-funct':1289 'legacy/process':1294 'legacyfunct':1286 'let':1369 'level':593,622,882,1049,1079,1097 'lifecycl':70 'limit':206,213,256,1028 'listen':793 'log':318,1033,1037,1078,1124,1142,1168,1184,1416 'log-complet':1183 'logger':1045,1047,1064,1066,1094,1114,1121,1140 'logger.info':1156,1173,1187 'logic':153,181,311,903 'loglevel':1107 'long':62 'long-run':61 'long/process.requested':766 'maintain':26 'manual/report.requested':546 'master':50 'match':703 'max':351 'maximum':214,221,228 'maxruntim':1224,1247 'memoiz':126,363 'method':1447 'mid':45 'mid-execut':44 'minut':776,785 'mistak':1400 'model':55,113 'monitor':1467 'ms':249 'multipl':164,469,1179 'must':10 'my-app':1061,1091 'my-fn':442,456,476,503,519,541 'name':614 'need':108,1284 'network':279 'never':300,336 'new':700,966,1025,1054,1058,1088,1095 'next':1438 'non':123,151,179,290,912,1405 'non-determinist':122,150,178,289,1404 'non-retri':911 'nonretriableerror':927,967,1430 'noon':531 'oper':287,292,313 'optim':1193,1476 'option':1108,1115 'order':334,719,816 'order/cancelled':725,743 'order/created':341,722 'organ':677 'origin':695 'output':238,241 'outsid':154,320,1169,1408,1413,1417 'overal':897 'overhead':250 'pari':532 'pass':1065 'pattern':686,1125,1301,1354,1455,1485 'payment':401,737,750 'per':218,347,641,643,675,840,849,871 'perform':1192,1475 'period':1208,1261 'persist':135,1206 'platform':1227,1233 'practic':1035 'premium':1337 'premium-process':1336 'prevent':127,598,915 'primari':1376 'primary-servic':1375 'primaryresult':1370,1372,1387,1398 'process':12,171,192,333,584,668,718,761,804,815,935,976,1132,1174,1188,1312,1338,1348,1362 'process-data':170,1131 'process-ord':332,717,814 'process-report':583 'process-us':934 'process-user-act':667 'process-with-timeout':760 'process-with-timestamp':191 'process/conditional':1315 'process/robust':1365 'process1':1269 'process2':1277 'processdata':174,202,1128 'processord':329,714 'processpay':751 'processpremiumfeatur':1340 'processreport':587 'processstandardfeatur':1350 'processus':931 'processuseract':664 'processwithtimeout':757 'produc':595 'proper':1036 'purchas':464 'pure':304 'python':83 'rate':1027 're':129,253 're-execut':128 'react':22 'read':282 'real':1240 'real-time-funct':1239 'realtime/process':1245 'realtimefunct':1236 'receiv':745 'recoveri':1353 'reduc':1211 'refer':86,707,1448 'references/checkpointing.md':1472,1473 'references/error-handling.md':1457,1458 'references/observability.md':1464,1465 'references/step-execution.md':1450,1451 'reliabl':860 'reliable-funct':859 'reliablefunct':856 'remov':1111 'report':572,585 'request':246,280 'resourc':821 'respectratelimit':986 'respons':1005 'response.data':1032 'response.headers':1020 'response.status':1010 'result':167,188,567,588,1149,1397 'result.length':1191 'result1':1264,1278 'result2':1272,1280 'resultcount':1190 'retri':14,140,143,296,342,346,829,831,839,847,852,865,870,889,916,924,960,978,1012,1022 'retriabl':913 'retry-aft':1021 'retryaft':1019,1029 'retryaftererror':982,1026 'return':173,201,223,579,586,822,973,1031,1163,1279,1326,1339,1349,1378,1393,1396 'reus':369 'robust':1361 'robust-process':1360 'robustprocess':1357 'run':18,63,163,199,220,232,639,655,1178,1343 'schedul':21 'secondari':1385 'see':704,1440,1449,1456,1463,1471,1492 'send':414,632,1488 'send-checkout-email':631 'send-confirm':413 'sendemail':416,628 'separ':244 'serverless':1226,1250 'servic':1377,1386,1392 'set':1228 'setup':1038,1470 'side':119,316,596,625 'side-effect':118 'simpl':309,1077 'singl':437 'skill':66,77,1479 'skill-inngest-durable-functions' 'skill._':1497 'smaller':261 'source-inngest' 'specif':97,1014 'standard':1347 'standard-process':1346 'start':768,773 'state':27,134,233,1207 'step':115,133,145,155,158,183,186,217,227,237,243,271,321,348,356,360,365,514,535,556,565,650,684,731,788,810,841,850,872,875,894,910,942,997,1139,1144,1170,1214,1256,1257,1267,1275,1299,1303,1318,1330,1368,1409,1414,1418,1423,1439,1443,1446,1454 'step.invoke':265,569 'step.run':169,190,275,303,377,385,398,405,412,582,747,818,946,999,1151,1182,1266,1274,1322,1335,1345,1374,1389 'step.sendevent':267 'step.sleepuntil':733 'stop':971 'strategi':590,1462 'structur':326 'succeed':922 'sunday':553 'surviv':11,136 'syntax':706 'throw':965,1024 'time':165,533,979,1015,1180,1241 'timeout':753,763,767,1234,1253 'timestamp':160,194,196,204 'timezon':516 'toler':60 'topic-agent-skill-repository' 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agents' 'topic-claude-code-skills' 'topic-cursor-skills' 'topic-openclaw-skills' 'total':834 'trace':1469 'track':888 'transform':308 'transport':1053 'tri':1371 'trigger':72,339,418,422,423,428,439,445,459,470,479,497,506,522,544,635,671,696,720,764,805,862,937,992,1134,1243,1292,1313,1363 'true':486 'twice':656 'typescript':81,148,327,364,436,498,559,597,626,712,755,792,854,925,980,1039,1126,1215,1305,1355 'tz':524 'uniqu':335,674 'upon':923 'use':5,270,319,392,578,1070,1112 'user':669,676,936,944,949,952,957,961,968,974,1160,1325 'user/action':461 'user/action.performed':673 'user/login':483 'user/process.requested':939 'user/signup':447,481 'user@example.com':619 'userdata':1320,1341,1351 'userdata.ispremium':1333 'userid':576,1161 'v4':1103,1201,1222 'valid':310,400 'validate-pay':399 'validatepay':402 'via':264 'wait':735 'wait-for-pay':734 'want':295 'warn':1101 'webhook':32,1490 'week':551 'winston':1041,1043 'winston.createlogger':1048 'winston.format.json':1052 'winston.transports.console':1055 'within':774,783 'won':653,920 'workflow':64,359 'wrap':273,301 'write':284 'www.inngest.com':92 'www.inngest.com/llms.txt)':91","prices":[{"id":"50d18f47-9a54-4685-99fa-4f7f765f5efc","listingId":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"inngest","category":"inngest-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T23:06:55.839Z"}],"sources":[{"listingId":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","source":"github","sourceId":"inngest/inngest-skills/inngest-durable-functions","sourceUrl":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-durable-functions","isPrimary":false,"firstSeenAt":"2026-04-18T23:06:55.839Z","lastSeenAt":"2026-05-18T19:05:31.101Z"},{"listingId":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","source":"skills_sh","sourceId":"inngest/inngest-skills/inngest-durable-functions","sourceUrl":"https://skills.sh/inngest/inngest-skills/inngest-durable-functions","isPrimary":true,"firstSeenAt":"2026-05-07T20:41:08.093Z","lastSeenAt":"2026-05-07T22:40:47.861Z"}],"details":{"listingId":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"inngest","slug":"inngest-durable-functions","github":{"repo":"inngest/inngest-skills","stars":22,"topics":["agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"license":"other","html_url":"https://github.com/inngest/inngest-skills","pushed_at":"2026-05-06T18:21:48Z","description":"Agent Skills for building with Inngest","skill_md_sha":"3b9383159c15eaa6f8ba0c49a713f71e2c4daf6b","skill_md_path":"skills/inngest-durable-functions/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-durable-functions"},"layout":"multi","source":"github","category":"inngest-skills","frontmatter":{"name":"inngest-durable-functions","description":"Use when building functions that must survive process crashes, retry automatically on failure, run on a schedule, react to events, or maintain state across infrastructure failures — e.g., webhook handlers that drop events, flaky cron jobs, background jobs that fail mid-execution, or workflows that need to resume where they left off. Covers Inngest function configuration, triggers (events, cron, invoke), step execution and memoization, idempotency, cancellation, error handling, retries, logging, and observability."},"skills_sh_url":"https://skills.sh/inngest/inngest-skills/inngest-durable-functions"},"updatedAt":"2026-05-18T19:05:31.101Z"}}