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
Code+-----------------------+ +---------------------------+ | 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
terminalcurl https://api.zavu.dev/v1/functions/$FN_ID \ -H "Authorization: Bearer $KEY" \ | jq '.function.runtimeLayerArn'
Code"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:
terminalcurl 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
terminalnpx 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 onv8.
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.
Bulk upgrade
When a security patch lands, you can sweep all your functions:
terminal# 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:
terminalfor 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.
{
"name": "my-function",
"zavu": {
"architecture": "x86_64"
},
"dependencies": {
"sharp": "^0.33.0"
}
}
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 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 oldsharp,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:
terminalgit 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.