{"id":"c459a360-6bc3-4bef-bdcc-93f06e4e436b","shortId":"ctLnXc","kind":"skill","title":"inngest-durable-functions","tagline":"Create and configure Inngest durable functions. Covers triggers (events, cron, invoke), step execution and memoization, idempotency, cancellation, error handling, retries, logging, and observability.","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.458","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 17 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-04-23T01:02:08.936Z","embedding":null,"createdAt":"2026-04-18T23:06:55.839Z","updatedAt":"2026-04-23T01:02:08.936Z","lastSeenAt":"2026-04-23T01:02:08.936Z","tsv":"'-1':1249 '-100':229 '-2':1257 '-80':1212 '/6':490 '/llms.txt)':74 '/references/expressions.md':689 '0':469,489,507,529,530,531,866 '000':197 '1':196,817,1384 '10':331,454,847,850 '100':447 '12':508 '2':1391 '24':592,625 '3':1396 '30':765 '30m':759 '32mb':210 '4':324,326,819,1402 '429':992 '4mb':203 '5':509,756,814,882,1408 '50':228 '50s':1229 '5m':750 '6':492,1413 '60':1211 '60s':1233 '9':470,473 'across':83 'action':651 'advanc':1281 'allow':1184 'alway':253,1323 'anoth':542 'anyth':274 'api':257,971,983,998 'api-cal':970 'api/call.requested':975 'app':1044,1074 'appli':82 'argument':414 'array':410 'async':137,165,335,429,448,475,494,515,535,629,663,679,710,767,789,854,921,931,976,984,1118,1136,1167,1235,1278,1297,1347 'async.data.orderid':709 'attempt':816,857,858,864,881,887 'automat':120,354 'avoid':1127,1148,1383 'await':149,170,357,365,378,385,392,549,562,585,713,727,798,926,934,979,987,1131,1145,1162,1246,1254,1302,1315,1325,1354,1369 'backoff':824 'bad':130 'base':670 'basic':305,480 'behavior':813 'best':1015 'break':238,1085 'build':38 'built':1054 'built-in':1053 'calcul':286 'call':258,972,982,1393 'call-api':981 'callprimaryservic':1360 'callsecondaryservic':1375 'cancel':21,666,671,722,735,751,760,771,776,784 'cancelon':704 'cart/checkout.completed':596,618 'cartid':591,598,623,640 'case':1412 'catch':1362 'caus':1400 'chang':318,1086,1403 'charg':388,730 'charge-custom':387 'charge-pay':729 'chargecustom':390 'checkout':589,614 'checkout-complet':588 'checkpoint':1175,1176,1197,1227,1243,1263,1276 'clariti':377 'cleanup':772,783,801 'cleanup-cancelled-process':782 'cleanup-resourc':800 'cleanupcancel':779 'cleanuporderresourc':804 'client':1049 'code':106,899,1388 'combin':211,517,659 'common':1380 'complet':50,113,590,1156,1166,1170 'complex':641 'comprehens':1441 'concept':81,87 'concurr':330,333 'condit':433,1283,1292,1310 'conditional-process':1291 'conditionalprocess':1288 'configur':7,123,834,1025,1204 'confirm':396 'connect':244 'consolelogg':1056,1063,1077,1098 'const':140,147,168,176,309,355,363,547,608,644,694,737,778,836,911,924,932,966,985,999,1027,1037,1067,1108,1129,1216,1244,1252,1266,1287,1300,1337 'consum':605 'continu':956 'control':1061 'core':80,86 'could':1158 'count':125 'counter':353,829,865 'cover':11,48,1461 'creat':5 'createfunct':416 'creation':304 'critic':1417 'critical/task':845 'cron':14,468,477,481,488,504,528 'current':873,890 'custom':389,583,832,958,1101 'daili':471 'data':153,205,217,288,356,361,369,556,561,597,1114,1135,1139 'data/process.requested':1117 'databas':262,1392 'date.now':142,178 'db.users.findone':935 'debug':1079,1080 'dedupl':594 'default':325,811,1180,1201 'defin':406 'deploy':1407 'descript':374 'detail':692,1426,1434,1458 'determinist':105,133,161,272,293,1387 'differ':371,883 'disabl':1262 'document':71 'doesn':943 'duplic':580,1128,1153,1401 'durabl':3,9,29,34,92,339,1464 'effect':101,298 'email':599,615 'enabl':1178,1199 'encapsul':98 'error':22,55,807,895,1083,1333,1363,1442 'europe/paris':506 'event':13,138,166,216,321,336,401,402,419,427,430,431,441,449,461,463,476,519,526,536,573,581,617,630,653,664,669,674,678,682,702,705,711,725,746,768,777,787,790,844,855,919,922,974,977,1116,1119,1225,1236,1274,1279,1295,1298,1345,1348,1468,1477 'event-bas':668 'event-level':572 'event.data':156,184,391,733,989,1251,1361,1376 'event.data.action':444 'event.data.amount':446 'event.data.cartid':628 'event.data.email':398 'event.data.firstlogin':466 'event.data.function':793 'event.data.orderid':708 'event.data.organizationid':662 'event.data.paymentdue':719 'event.data.paymentid':384 'event.data.run':805 'event.data.userid':558,661,936,1143,1147,1309 'everi':188,491 'execut':17,35,93,111,127,334,372,874,953,1191,1239,1285,1312 'exist':945 'exponenti':823 'express':673,686 'externalapi.call':988 'failur':119,280 'fallback':1364,1372 'fallback-servic':1371 'fals':1277 'fault':40 'fault-toler':39 'fetch':360,368,929,1134,1138,1305 'fetch-data':359,367,1133 'fetch-us':928,1304 'fetchorderdata':370 'fetchuserdata':362,1146 'file':266 'filter':434 'finish':758,763 'first':413 'flow':128 'fn':425,439,459,486,502,524 'focus':60 'format':1032 'found':951 'friday':510 'full':691 'function':4,10,30,186,190,200,212,221,240,243,303,306,538,543,554,602,633,842,862,879,1104,1185,1223,1272,1418,1465 'function-level':601,861 'generat':552 'generate-report':551 'generatereportfunct':555 'getuserdata':1308 'go':66 'good':157,1122 'guidanc':79 'handl':23,56,352,770,808,1410,1472 'hard':193 'hit':235 'hour':493,593,626 'http':226 'i/o':267 'id':312,342,347,375,422,436,456,483,499,521,584,587,611,647,697,740,781,794,806,839,914,969,1041,1071,1111,1219,1269,1290,1340,1405 'idempot':20,570,575,604,627,642,660,1415 'ignor':1414 'immedi':1240 'import':907,962,1021,1062 'includ':215 'independ':278,827 'index':867 'info':1031,1081 'infrastructur':118 'initi':818 'inngest':2,8,28,32,70,189,351,910,965,1038,1040,1064,1066,1068,1070,1423,1462,1476 'inngest-durable-funct':1 'inngest-ev':1475 'inngest-step':1422 'inngest.createfunction':311,421,435,455,482,498,520,610,646,696,739,780,838,913,968,1110,1218,1268,1289,1339 'inngest.send':586 'inngest/function.cancelled':788 'insid':1124 'instead':1103 'invoc':539 'invok':15,541 'jitter':826 'key':643 'know':91 'languag':77,85 'language-specif':76 'latenc':1193 'later':886 'legaci':1271 'legacy-funct':1270 'legacy/process':1275 'legacyfunct':1267 'let':1350 'level':574,603,863,1030,1060,1078 'lifecycl':51 'limit':187,194,237,1009 'listen':774 'log':25,299,1014,1018,1059,1105,1123,1149,1165,1397 'log-complet':1164 'logger':1026,1028,1045,1047,1075,1095,1102,1121 'logger.info':1137,1154,1168 'logic':134,162,292,884 'loglevel':1088 'long':43 'long-run':42 'long/process.requested':747 'manual/report.requested':527 'master':31 'match':684 'max':332 'maximum':195,202,209 'maxruntim':1205,1228 'memoiz':19,107,344 'method':1428 'minut':757,766 'mistak':1381 'model':36,94 'monitor':1448 'ms':230 'multipl':145,450,1160 'my-app':1042,1072 'my-fn':423,437,457,484,500,522 'name':595 'need':89,1265 'network':260 'never':281,317 'new':681,947,1006,1035,1039,1069,1076 'next':1419 'non':104,132,160,271,893,1386 'non-determinist':103,131,159,270,1385 'non-retri':892 'nonretriableerror':908,948,1411 'noon':512 'observ':27 'oper':268,273,294 'optim':1174,1457 'option':1089,1096 'order':315,700,797 'order/cancelled':706,724 'order/created':322,703 'organ':658 'origin':676 'output':219,222 'outsid':135,301,1150,1389,1394,1398 'overal':878 'overhead':231 'pari':513 'pass':1046 'pattern':667,1106,1282,1335,1436,1466 'payment':382,718,731 'per':199,328,622,624,656,821,830,852 'perform':1173,1456 'period':1189,1242 'persist':116,1187 'platform':1208,1214 'practic':1016 'premium':1318 'premium-process':1317 'prevent':108,579,896 'primari':1357 'primary-servic':1356 'primaryresult':1351,1353,1368,1379 'process':152,173,314,565,649,699,742,785,796,916,957,1113,1155,1169,1293,1319,1329,1343 'process-data':151,1112 'process-ord':313,698,795 'process-report':564 'process-us':915 'process-user-act':648 'process-with-timeout':741 'process-with-timestamp':172 'process/conditional':1296 'process/robust':1346 'process1':1250 'process2':1258 'processdata':155,183,1109 'processord':310,695 'processpay':732 'processpremiumfeatur':1321 'processreport':568 'processstandardfeatur':1331 'processus':912 'processuseract':645 'processwithtimeout':738 'produc':576 'proper':1017 'purchas':445 'pure':285 'python':64 'rate':1008 're':110,234 're-execut':109 'read':263 'real':1221 'real-time-funct':1220 'realtime/process':1226 'realtimefunct':1217 'receiv':726 'recoveri':1334 'reduc':1192 'refer':67,688,1429 'references/checkpointing.md':1453,1454 'references/error-handling.md':1438,1439 'references/observability.md':1445,1446 'references/step-execution.md':1431,1432 'reliabl':841 'reliable-funct':840 'reliablefunct':837 'remov':1092 'report':553,566 'request':227,261 'resourc':802 'respectratelimit':967 'respons':986 'response.data':1013 'response.headers':1001 'response.status':991 'result':148,169,548,569,1130,1378 'result.length':1172 'result1':1245,1259 'result2':1253,1261 'resultcount':1171 'retri':24,121,124,277,323,327,810,812,820,828,833,846,851,870,897,905,941,959,993,1003 'retriabl':894 'retry-aft':1002 'retryaft':1000,1010 'retryaftererror':963,1007 'return':154,182,204,560,567,803,954,1012,1144,1260,1307,1320,1330,1359,1374,1377 'reus':350 'robust':1342 'robust-process':1341 'robustprocess':1338 'run':44,144,180,201,213,620,636,1159,1324 'secondari':1366 'see':685,1421,1430,1437,1444,1452,1473 'send':395,613,1469 'send-checkout-email':612 'send-confirm':394 'sendemail':397,609 'separ':225 'serverless':1207,1231 'servic':1358,1367,1373 'set':1209 'setup':1019,1451 'side':100,297,577,606 'side-effect':99 'simpl':290,1058 'singl':418 'skill':47,58,1460 'skill-inngest-durable-functions' 'skill._':1478 'smaller':242 'source-inngest' 'specif':78,995 'standard':1328 'standard-process':1327 'start':749,754 'state':115,214,1188 'step':16,96,114,126,136,139,164,167,198,208,218,224,252,302,329,337,341,346,495,516,537,546,631,665,712,769,791,822,831,853,856,875,891,923,978,1120,1125,1151,1195,1237,1238,1248,1256,1280,1284,1299,1311,1349,1390,1395,1399,1404,1420,1424,1427,1435 'step.invoke':246,550 'step.run':150,171,256,284,358,366,379,386,393,563,728,799,927,980,1132,1163,1247,1255,1303,1316,1326,1355,1370 'step.sendevent':248 'step.sleepuntil':714 'stop':952 'strategi':571,1443 'structur':307 'succeed':903 'sunday':534 'surviv':117 'syntax':687 'throw':946,1005 'time':146,514,960,996,1161,1222 'timeout':734,744,748,1215,1234 'timestamp':141,175,177,185 'timezon':497 'toler':41 'topic-agent-skill-repository' 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agents' 'topic-claude-code-skills' 'topic-cursor-skills' 'topic-openclaw-skills' 'total':815 'trace':1450 'track':869 'transform':289 'transport':1034 'tri':1352 'trigger':12,53,320,399,403,404,409,420,426,440,451,460,478,487,503,525,616,652,677,701,745,786,843,918,973,1115,1224,1273,1294,1344 'true':467 'twice':637 'typescript':62,129,308,345,417,479,540,578,607,693,736,773,835,906,961,1020,1107,1196,1286,1336 'tz':505 'uniqu':316,655 'upon':904 'use':251,300,373,559,1051,1093 'user':650,657,917,925,930,933,938,942,949,955,1141,1306 'user/action':442 'user/action.performed':654 'user/login':464 'user/process.requested':920 'user/signup':428,462 'user@example.com':600 'userdata':1301,1322,1332 'userdata.ispremium':1314 'userid':557,1142 'v4':1084,1182,1203 'valid':291,381 'validate-pay':380 'validatepay':383 'via':245 'wait':716 'wait-for-pay':715 'want':276 'warn':1082 'webhook':1471 'week':532 'winston':1022,1024 'winston.createlogger':1029 'winston.format.json':1033 'winston.transports.console':1036 'within':755,764 'won':634,901 'workflow':45,340 'wrap':254,282 'write':265 'www.inngest.com':73 'www.inngest.com/llms.txt)':72","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-04-23T01:02:08.936Z"}],"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":17,"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-04-20T23:35:15Z","description":"Agent Skills for building with Inngest","skill_md_sha":"44ab8081b7a81e43300b7030af666d34594a1d65","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":"Create and configure Inngest durable functions. Covers 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-04-23T01:02:08.936Z"}}