> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nelkap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How Nelkap works

> The execution model behind every run: who runs your code, how a run moves forward call by call, and what Nelkap guarantees.

Nelkap makes an ordinary async function durable. The function can stop at any point, for a crash, a deploy, or a pause of several months, and resume exactly where it stopped. This page explains the model behind it. Knowing it tells you how to write workflows that behave the way you expect.

## Architecture

Three parts work together. Your code never leaves your app.

| Part | Where it runs | What it does |
| - | - | - |
| Your app | Your servers or your host | Holds your workflows and the route Nelkap calls. |
| The SDK | Inside your app | Runs your workflows, saves each step to Nelkap, and answers Nelkap's calls. |
| Nelkap | Nelkap's cloud | Stores every run, step, and event. Decides when each run is due, and calls your app to execute it. |

Nelkap keeps the state of each run: its payload, the result or error of each step, and what the run is waiting for. Your app keeps nothing between two calls, so it can restart, scale out, or be redeployed at any time.

## Calls

Nelkap executes a run through calls. A call is one POST request from Nelkap to your project's endpoint, the route where your app passes requests to [`nelkap.handle`](https://docs.nelkap.com/reference/handle). Each call carries:

| Part | Content |
| - | - |
| `Authorization` header | `Bearer` followed by your project's secret. `handle` turns down a call without it. |
| `workflowName` | The workflow to run. |
| `runId` | The run's ID. |
| `payload` | The run's payload, the argument your workflow receives. |
| `steps` | Every step the run has saved so far, with its result or error. |

`handle` answers `202` at once, then runs the workflow in the background. Nelkap never waits for your workflow to finish, however long it takes.

A run takes one call for each stretch of work between two pauses. A workflow that never sleeps or waits runs in a single call. A workflow with one sleep runs in two calls: one before the sleep, one after.

## Run lifecycle

Here is the `onboardUser` workflow from the [quickstart](https://docs.nelkap.com/quickstart.md). It creates a profile, sleeps for a day, then sends a welcome email:

![The onboardUser run over two calls: on day 1, the profile step runs and the run sleeps; on day 2, the profile step returns its saved result and the welcome step runs.](https://mintcdn.com/holotus/zu12qw3F64kRzbLL/images/run-calls-light.png?fit=max\&auto=format\&n=zu12qw3F64kRzbLL\&q=85\&s=c4ceff345630a4d122f072e7b9790154)

1. Your app starts the run with `nelkap.run`. Nelkap records it as pending.
2. Within a minute, Nelkap calls your endpoint with the run's payload and no saved steps.
3. The `profile` step runs, and the SDK saves its result to Nelkap.
4. The workflow reaches the sleep. The SDK tells Nelkap when the run should wake, and the call ends. Nothing runs in your app for a day.
5. When the day is over, Nelkap calls your endpoint again, this time with the saved `profile` step.
6. Your workflow runs from its first line. The `profile` step returns its saved result without running. The sleep is over, so the `welcome` step runs, its result is saved, and the run completes.

Each status a run goes through, from pending to completed, is described in [Runs](https://docs.nelkap.com/concepts/runs.md#lifecycle).

## Memoization

On every call, the SDK runs your workflow function from its first line. Each time the code reaches a step, the SDK looks for that step among the saved ones:

* If the step is saved, it returns its saved result at once, or throws its saved error, without running.
* If it isn't, it runs, and its result is saved before the code moves on.

Your code therefore moves quickly through everything done in earlier calls, and the real work starts at the first step with no saved result. This is what makes a saved step's work happen only once per run.

> [!WARNING]
>
> Code outside steps runs again on every call, so it must take the same path each time. Anything that can change between two calls, like the current time, a random value, or a database read, belongs in a step. See [Determinism](https://docs.nelkap.com/concepts/steps.md#determinism).

## Sleeps and waits

A sleep or a wait ends the call. Nelkap keeps the run, and your app has nothing running and nothing in memory, whether the pause lasts a minute or a year:

* A sleeping run wakes when its time is up. Nelkap checks the timers every minute.
* A waiting run wakes when your app emits an event with the key it waits on.

Either way, Nelkap calls your endpoint again, and the run resumes after the pause. See [Sleep](https://docs.nelkap.com/guides/sleep.md) and [Wait for an event](https://docs.nelkap.com/guides/wait.md).

## Failure recovery

While a call runs, the SDK sends Nelkap a heartbeat every minute. Nelkap uses it to tell a long step from a dead app. Each kind of failure is handled for you:

| What happens | What Nelkap does |
| - | - |
| Your app crashes or is redeployed in the middle of a call. | The heartbeat stops. After five minutes without one, Nelkap calls your app again, and the run resumes from its last saved step. |
| Your host stops the function at its time limit. | Same as a crash: the run resumes about five minutes later. |
| Your endpoint is unreachable, or answers with an error. | Nelkap tries again about a minute and a half later. After three failed attempts, the run fails with `deliveryFailed`. |
| The SDK can't reach Nelkap to save a step. | The run stops where it is, and resumes about five minutes later. It doesn't fail. |
| A step's function throws. | The error is saved like a result, and your workflow decides what happens next. See [Error handling](https://docs.nelkap.com/guides/failures.md). |

A step cut off before its result was saved runs again from its start when the run resumes. See [At-least-once execution](https://docs.nelkap.com/concepts/steps.md#at-least-once-execution).

## Guarantees

| Guarantee | What it means for your code |
| - | - |
| A saved step never runs again in its run. | A step that charged a card, once saved, never charges it again in that run. |
| Every step runs at least once. | A step cut off before it was saved runs again. Make steps with side effects safe to repeat. See [Idempotency](https://docs.nelkap.com/guides/idempotency.md). |
| Steps are matched in the order your code reaches them. | Steps in loops and in `Promise.all` find their saved results in the right order. |
| A run cut off by a crash or a deploy resumes. | You don't write recovery code. The run resumes from its last saved step, on the code your app runs at that moment. |
| Every call carries your project's secret. | `handle` runs nothing for a request that doesn't come from Nelkap. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.