Limits and quotas
The platform defaults that bound every app's deploy size, compute, timers, terminal I/O, and outbound fetch
Every voxal app runs inside its own sandbox with a fixed set of limits. These bound deploy
size, compute, timers, terminal output, and outbound fetch. The values below are the
platform defaults.
Why these exist
Many apps and many users share one box. These limits keep one app, or one runaway connection, from starving everyone else, so every app gets a fair, predictable share of memory, CPU, and bandwidth.
Deploy and bundles
Your app, the SDK, and your pure-JS dependencies are bundled into a single file by the CLI. See voxal deploy and voxal build.
| Limit | Value | Notes |
|---|---|---|
| Bundle hard limit | 5 MiB (5,242,880 bytes) | Measured as UTF-8 bytes of the built bundle. Deploy or build fails over this. |
| Bundle warning | 4 MiB | A warning prints when the bundle exceeds 4 MiB. |
| Dependencies | Pure JavaScript only | No native npm modules. |
| Integrity | Checksum-verified end to end | The bundle is integrity-checked from build to boot, so the bytes that run are exactly the bytes you built. |
For app design: keep dependencies lean and tree-shakeable. If you are near the warning, audit large libraries before you hit the hard limit.
Compute and memory
Each app runs in its own isolate: a separate heap and event loop. One bad app cannot affect another or the host.
| Limit | Value | Notes |
|---|---|---|
| Memory per app | 64 MiB | The whole app's budget, shared across all of its connections. |
| CPU per boot | about 1000 ms | Synchronous JS only. Awaiting does not count against it. |
| CPU per event | about 100 ms | Each connect, key, resize, close, or timer fire. Synchronous JS only. |
| Idle timeout | 2 minutes | An app with no connections is dropped after 2 minutes idle. |
| Cold boot | about a few milliseconds | The app is booted again on the next connection. |
Long synchronous work is interrupted when it exceeds the per-call budget, so keep per-keystroke work small and avoid blocking the event loop. App memory is not retained across a drop: treat each boot as a fresh start and reload any state you need.
Timers
setTimeout and setInterval inside an app create real host timers, so they are bounded.
| Limit | Value | Notes |
|---|---|---|
| Live timers per app | 1024 | Exceeding this throws. |
| Minimum delay | 4 ms | Shorter delays are clamped up to 4 ms. |
| Aggregate fire rate | about 2000 fires/second per app | Exceeding this throws. |
Tip
If you animate with the UI layer, useAnimation shares a single timer across your component
tree, which stays well within these limits. See the UI layer.
Terminal I/O
Output you write to the terminal and input you receive from the user are both rate limited.
| Limit | Value | Notes |
|---|---|---|
Single conn.write | 1 MiB | The cap on one write call. |
| Sustained output | about 2 MiB/s, 4 MiB burst | Excess is dropped. Redraw efficiently. |
console.log per line | about 2048 characters | Truncated and rate limited. Goes to server logs, not the user's terminal. |
| Terminal columns | max 1000 | Default 80 when unknown. |
| Terminal rows | max 1000 | Default 24 when unknown. |
| Keyboard input | about 256 KiB/s sustained, 1 MiB burst | Per connection. Far above human typing; only affects pathological floods. |
For app design: diff your frames instead of repainting the whole screen, so you stay under the output cap. The UI layer does this for you. Because output past the cap is dropped, not buffered, an inefficient redraw can visibly corrupt the screen under load.
fetch
fetch is host-bridged and SSRF-guarded. The full reference, including options and the
response shape, is in the fetch docs.
| Limit | Value | Notes |
|---|---|---|
| Schemes | http, https only | All other schemes are refused. |
| Request timeout | 10 seconds | Total, per request. |
| Response size cap | 5 MiB | The body is truncated or aborted past this. |
| Redirects | up to 5 hops | Each hop re-validated. |
| Per-app rate limit | 30 requests per 10 seconds | Shared across the app's connections. |
| Concurrency | at most 6 in-flight | Per app. |
Private, loopback, link-local, and cloud-metadata addresses are refused, so a deployed app cannot reach internal services. See Sandbox and security for the full guard list.
The response is { status, headers (names lower-cased), body (UTF-8 string) }. A non-2xx
status does not throw, and errors are sanitized so no host details leak.