---
title: Runtime compatibility
description: "Which JavaScript APIs and npm packages have been tested in Sproutboat handlers."
---

Sproutboat's JavaScript and npm compatibility comes from [Porffor](https://porffor.dev)'s compiler and runtime work, together with [Sproutboat's architecture](/concepts/architecture): the CLI bundles and checks imports, and the native host supplies HTTP and bindings. The result is a compiled handler with a specific API surface, not a Node or Deno runtime. A package working in Porffor alone does not establish that it works in a Sproutboat handler, or vice versa.

The results below concern code **inside the handler**. The CLI's build environment has a different set of APIs. A successful bundle is only the first step: an imported package must also compile and behave correctly in the native sprout.

## Runtime APIs

| Surface | Handler support | Scope |
| --- | --- | --- |
| JavaScript and Web APIs | Partial | Common synchronous JavaScript, `URL`, `Request`, `Response`, `Headers`, `FormData`, text encoding, the Cache API and selected crypto operations work. See [The handler](/concepts/handler) for the tested surface. |
| Sproutboat bindings | Supported where documented | Use `env.*` for storage, secrets, and other configured services. Binding calls are synchronous before the compatibility date that makes each one return a Promise (D1 `2026-10-24`, KV `2026-10-25`, R2 `2026-10-26`); see [Bindings](/bindings). |
| Node APIs | Limited | `node:path`, `node:url` and `node:querystring` imports work through built-in shims. Other Node built-ins, `process`, `Buffer`, `require()` and filesystem access are unavailable. |
| Deno APIs | Unsupported | The `Deno` global and Deno runtime APIs are unavailable. Standard Web APIs used by Deno code may work when listed here. |
| Web Streams | Tested in memory | ReadableStream, WritableStream and TransformStream support reading, piping, transforms, tee, cancellation and BYOB reads. HTTP bodies remain buffered; stream BodyInit and progressive responses are unsupported. |
| WebSockets | Unsupported | No WebSocket handler in the current `http-sync-v0` profile. |
| `Proxy` | Tested operations | CLI 0.17.0 uses Porffor alpha-17, retaining alpha-16 Proxy support. Native checks cover object traps, function calls, construction, revocation and a frozen-property invariant. Package support remains specific to the operations tested below. |

## Performance

The [runtime comparison](https://sproutboat.com/#compare) runs the same Worker-style app on Node, workerd and a released Sproutboat executable on one Linux host, with raw samples and the method linked from the results.

## npm package results

These results were checked on **2026-09-25 with CLI 0.11.12**, using native standalone builds. The three packages that failed were rechecked on **2026-09-30 with CLI 0.12.0**. “Passed” means the listed operation returned the expected result in that test. It does not certify every export, input, dependency version, or deployment mode of the package.

| Package | Version | Tested operation | Result |
| --- | --- | --- | --- |
| `cookie` | 2.0.1 | Parse and serialize cookies | Passed |
| `path-to-regexp` | 8.4.2 | Match a route | Passed |
| `hono` | 4.13.9 | Answer a simple route | Passed; broader Hono behavior untested |
| `valibot` | 1.5.0 | `safeParse` | Passed |
| `zod` | 4.6.5 | `safeParse` with valid and invalid object input | Passed; broader Zod behavior untested |
| `nanoid` | 6.0.1 | Generate an ID | Passed |
| `uuid` | 14.0.2 | Generate a v4 ID | Passed |
| `ms` | 2.1.3 | Parse a duration | Passed |
| `date-fns` | 4.4.0 | Format an epoch timestamp | Passed |
| `is-path-inside` | 4.0.0 | Check a nested, sibling and identical path | Passed, through the `node:path` shim |
| `qs` | 6.16.0 | Nested query parse and stringify | Passed with CLI 0.16.0 |
| `itty-router` | 5.0.24 | `IttyRouter`: GET parameters, Unicode POST body and 404 fallback | Passed with CLI 0.16.0; standard `Router` still fails to compile around labelled iterator breaks |
| `@trpc/server` | 11.19.0 | `initTRPC`, router and `createCaller().hello()` | Passed with CLI 0.16.0; HTTP adapters, clients, middleware and subscriptions untested |
| `better-auth` | 1.7.1 | Email/password signup, signed-cookie session lookup, wrong-password rejection, signin, signout and revocation | Passed with an explicit memory adapter and default hashing; see limits below |
| `mime-types` | 3.0.2 | Bundle | Failed: calls `require("path")` |

The `qs`, `itty-router` and tRPC probes were checked on **2026-10-10 with CLI 0.16.0**, using native standalone builds. Collection iterator methods and `matchAll` now expose `next()` and `done`. `URLSearchParams` and `FormData` support live iteration, including entries appended after creating the iterator. String iteration still splits emoji and other astral characters into UTF-16 halves.

Better Auth was checked on **2026-10-11** using an optimized native standalone
build and pinned dependencies, including noble hashes 2.4.0 and zod 4.6.5.
The memory adapter is test storage; production database adapters, OAuth and
plugins are untested. Default password hashing takes about six seconds on the
development machine. Database-free sessions select encrypted JWE and still
require unsupported AES. The repeatable fixture is in
[the CLI integration probe](https://github.com/baronunread/sproutboat-cli/tree/main/bench/better-auth).

Alpha 17 fixes number conversion, Math.round ties and signed zero, console
precision and class-field captures. The newer unreleased TextEncoder commit
passes native Unicode checks and may replace our encoder patch in the next
release. See [the upgrade audit](https://github.com/baronunread/sproutboat-packages/blob/main/packages/toolchain/PORFFOR_ALPHA17.md).

These are deliberately narrow results. In particular, a simple Hono route does not establish that every Hono feature works, and Zod's basic validation result does not establish compatibility for packages built on Zod.

## Check a dependency for your handler

1. Pin the package version and import the operations you actually use from your handler.
2. Run `sproutboat check` and `sproutboat build --standalone`. A passing check alone does not prove native runtime behavior.
3. Run the standalone sprout and send requests that cover both success and failure paths. Repeat on the deployed platform if your code uses broker-backed bindings.

When reporting a failure, include the CLI and package versions, the smallest handler that reproduces it, whether bundling, compilation, startup, or a request failed, and whether it occurred in standalone or deployed mode. This helps distinguish an upstream Porffor limitation from a Sproutboat bundle, shim, or binding issue.
