# Runtime versions

> How runtime pinning works and when to upgrade.

## Runtime versions

Each Zavu Function is built against a specific **runtime version** — a sealed
bundle containing `@zavudev/functions`, our SDK, and a small set of curated
libraries. Runtime versions are immutable: once a function is deployed against
runtime `v7`, it keeps using that exact version forever, even if we publish
newer ones.

This means your function is **stable**. We can iterate the runtime without
breaking what's already live.

Throughout this page `v7` and `v8` are shorthand. The identifier the API
returns is the runtime layer's ARN, whose trailing number is that version.

## How pinning works

```
+-----------------------+        +---------------------------+
| You: npx zavudev deploy      | -----> | Function pinned to v7     |
+-----------------------+        +---------------------------+
                                              ^
                                              |
                                          (forever)
+-----------------------+
| Zavu: publishes v8    |
+-----------------------+

# Your function is still on v7. Unaffected.

+--------------------------------+        +--------------------------+
| You: npx zavudev deploy --update-runtime| ---->| Function now pinned to v8|
+--------------------------------+        +--------------------------+
```

- **First deploy**: function is pinned to whatever the latest runtime version
  was at deploy time.
- **Subsequent deploys** (`npx zavudev deploy`): keep the same pin. The runtime
  doesn't change even if newer versions are available.
- **Opt-in upgrade** (`npx zavudev deploy --update-runtime`): bump to the latest.

## Checking your pin

```sh
curl https://api.zavu.dev/v1/functions/$FN_ID \
  -H "Authorization: Bearer $KEY" \
  | jq '.function.runtimeLayerArn'
```

```
"arn:aws:lambda:us-east-1:000000000000:layer:zavu-nodejs24:7"
```

The pin is the runtime layer the function is bound to. The same value across
deploys means the same runtime; `null` means the function has never deployed.

## Auditing per-deployment

Every deployment record stores which runtime ran:

```sh
curl https://api.zavu.dev/v1/functions/deployments/$DEPLOYMENT_ID \
  -H "Authorization: Bearer $KEY" \
  | jq '.deployment | {version, runtimeLayerArn, deployedAt}'
```

```json
{
  "version": 4,
  "runtimeLayerArn": "arn:aws:lambda:us-east-1:000000000000:layer:zavu-nodejs24:7",
  "deployedAt": "2026-04-12T14:23:00.000Z"
}
```

Useful for "which deploy was on which runtime when the bug happened?".

## Upgrading

```sh
npx zavudev deploy --update-runtime
```

This deploys the current source code AGAINST the latest runtime version. If
the latest is `v8` and you were pinned to `v7`:

- The function's runtime pin moves to `v8`.
- All subsequent `npx zavudev deploy` (without the flag) keep you on `v8`.

## When you should upgrade

Most of the time, never. Stay pinned. Upgrade only when:

| Reason | Action |
|---|---|
| **Security advisory** for your current runtime | Upgrade immediately. We'll email you. |
| **New feature** you want (`defineFlow`, new SDK methods, etc.) | Upgrade when convenient. |
| **Curated dep version bump** that fixes a bug affecting you | Upgrade. |
| **Performance improvements** in cold-start, bundle size | Upgrade when convenient. |
| Nothing changed and the new version is just a refactor | Don't bother. |

## When you should NOT upgrade

- **Breaking change in the framework** that touches a method you use. Read
  the changelog first. Upgrade after fixing your code.
- **Dependency bump** in a curated lib (zod, hono, etc) — if your code
  depends on specific behavior, test first.

## Support policy

There is one current runtime layer at a time. Older layers are not tracked with
a lifecycle status, and no deploy is ever refused because its pin is old.

> **Note:**
> Deployed functions keep their pinned runtime indefinitely. A newer layer being
> published does not move, patch or retire a function already pinned to an older
> one — only a deploy with `--update-runtime` changes the pin.

## Bulk upgrade

When a security patch lands, you can sweep all your functions:

```sh
# List all (we'll add `--outdated` filter soon; for now use the API)
npx zavudev senders list      # to find sender IDs
npx zavudev agents executions # for activity insight

# Per function:
cd ./my-function
npx zavudev deploy --update-runtime
```

For programmatic bulk migration:

```sh
for fn_id in $(curl -s https://api.zavu.dev/v1/functions \
  -H "Authorization: Bearer $KEY" \
  | jq -r '.items[].id'); do
  curl -X POST "https://api.zavu.dev/v1/functions/$fn_id/deploy" \
    -H "Authorization: Bearer $KEY" \
    -d '{"updateRuntime":true}'
done
```

## What's actually in a runtime version

The current runtime (~3 MB) contains:

| Package | Version range | Purpose |
|---|---|---|
| `@zavudev/functions` | platform-bundled | `defineFunction`, `defineAgent`, `defineTool`, `verifyWebhook` |
| `@zavudev/sdk` | latest stable | Call Zavu APIs |
| `zod` | ^3.22 | Schema validation |
| `hono` | ^4 | HTTP-friendly utilities |
| `dayjs` | ^1 | Date manipulation |
| Node built-ins | — | `fetch`, `crypto`, `Buffer`, etc. |

If you `import` one of these in your function source code, esbuild marks it
as external and the runtime resolves it at execution time — no `npm install`
needed, no bundle bloat.

To use a package NOT in the bundled set, declare it in `package.json` and the
build worker installs it during `npx zavudev deploy`:

```json
{
  "dependencies": {
    "openai": "^4.20.0"
  }
}
```

## CPU architecture

Each function runs on **arm64** by default (AWS Graviton). You can opt into **x86_64** when an npm dependency requires it:

| Architecture | Compute cost | When to use |
|---|---|---|
| `arm64` (default) | 1.00× | All pure-TypeScript code and any native module with modern arm64 prebuilds. |
| `x86_64` | 1.25× | Some image / crypto / wasm libs only publish x86 prebuilts. Bumps every invocation by 25% units. |

### Setting it

Pick whichever fits your workflow — they compose, with CLI flag > package.json > server default.

```json
{
  "name": "my-function",
  "zavu": {
    "architecture": "x86_64"
  },
  "dependencies": {
    "sharp": "^0.33.0"
  }
}
```

```sh
npx zavudev deploy --arch x86_64
```

```text
Function detail → Settings → CPU architecture → x86_64
```

The change applies on the next `npx zavudev deploy` — Lambda doesn't allow swapping architecture in-place, so a new function deployment is required.

### Pricing impact

The architecture multiplier compounds with the memory multiplier. Examples:

| Memory | arm64 units / call | x86_64 units / call |
|---|---|---|
| 128 MB | 1.00 | 1.25 |
| 256 MB | 2.00 | 2.50 |
| 512 MB | 4.00 | 5.00 |
| 1024 MB | 8.00 | 10.00 |

If you're approaching your plan's monthly quota, prefer arm64 first — switch to x86 only when you've confirmed a specific dep needs it. See [Pricing model](https://www.zavu.dev/docs/concepts/functions#pricing-model) for plan quotas.

### When you actually need x86

Modern packages (most of npm) ship arm64 prebuilts. You generally only need x86 for:

- Older versions of native libs (`bcrypt < 5`, very old `sharp`, `canvas`)
- Wasm-wrapped tools without arm64 bindings
- Code that uses `process.arch === "x64"` assumptions

A `npx zavudev deploy` on arm64 with an incompatible package usually fails with a clear "Could not find prebuild for ... arm64" error — that's your cue to switch.

## Rolling back

We don't have a `--runtime <version>` flag yet for explicit version pinning.
If an upgrade breaks you, the workaround is to deploy from a previous source
commit **without** `--update-runtime`:

```sh
git checkout <pre-upgrade-commit>
npx zavudev deploy   # uses the pinned runtime, no flag → keeps current pin
```

If the pin is already on the broken version, the most reliable rollback is
to delete and recreate the function with the previous runtime explicitly
provisioned by Zavu support.

> **Tip:**
> This is rare in practice — runtime upgrades are tested in our staging
> environment before public release. But if you hit it, contact support and
> we'll help with the manual repin.
