# awslabs/llrt: a Rust and QuickJS runtime for Lambda cold starts

> LLRT is an experimental AWS Labs JavaScript runtime built on QuickJS that targets Lambda cold start latency. It is not a Node.js replacement, and the compatibility matrix shows exactly where it stops.

**awslabs/llrt** — LLRT (Low Latency Runtime) is an experimental, lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications.

- Repository: https://github.com/awslabs/llrt
- Stars: 8,805 · Forks: 397
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/awslabs-llrt

## The cold start problem LLRT is aimed at

A Lambda function that runs for 50 ms can still cost the caller a second of wall clock time if the runtime has to initialize first. LLRT (Low Latency Runtime) targets that gap. The README positions it as a runtime for fast and efficient serverless applications and claims up to over 10x faster startup and up to 2x overall lower cost compared to other JavaScript runtimes running on AWS Lambda. Those numbers come from the project's own benchmarks, and the README links to a benchmark methodology section, so treat them as vendor measurements rather than independent results.

The intended audience is narrow and worth stating plainly. This is for teams already running JavaScript on Lambda who have a handler that spends a meaningful share of its time on initialization rather than work. It is not for teams looking for a faster local development runtime, and it is not a general purpose Node.js substitute. The README carries a warning that LLRT is an experimental package, subject to change, and intended only for evaluation purposes. That warning is the single most important line in the repository.

## QuickJS plus Rust modules: what is actually inside

LLRT uses QuickJS as its JavaScript engine and is written in Rust. The workspace in Cargo.toml shows the shape of the project: a libs/ directory with small crates such as llrt_utils, llrt_json, llrt_encoding and llrt_compression, and a modules/ directory with one crate per Node.js API surface. There is llrt_fs, llrt_net, llrt_crypto, llrt_stream, llrt_timers, llrt_url, llrt_zlib and roughly two dozen more. The two top-level crates are llrt_core and llrt.

That layout explains the compatibility story. Each Node.js module is a separate Rust implementation rather than a shared compatibility layer, so coverage is uneven by construction. The compatibility matrix in the README marks entries with three states: a check for supported, a check with a warning sign for partial support, and a cross for unsupported. node:assert, node:buffer, node:crypto, node:fs, node:path and node:process are all in the partial column. node:cluster, node:dgram, node:diagnostics_channel, node:http2 and node:inspector are unsupported. node:http and node:https are marked unsupported with a clock symbol, which the README does not expand in the text shown here.

The release profile in Cargo.toml is tuned for binary size and startup: strip, link time optimization, codegen-units = 1, opt-level = 3 and panic = "abort". That combination is consistent with a runtime that wants to start fast and stay small.

## Installing LLRT and running a first handler

There is no npm install for the runtime itself. The README says to download the last LLRT release from the GitHub releases page, then points at five deployment options for Lambda. Option 1, described as recommended, is a custom runtime: choose Custom Runtime on Amazon Linux 2023 and package the LLRT bootstrap binary together with your JS code. Option 2 uploads llrt-lambda-arm64.zip or llrt-lambda-x64.zip as a layer. Option 3 packages LLRT in a container image, and the README gives this Dockerfile:

```dockerfile
FROM --platform=arm64 busybox
WORKDIR /var/task/
COPY app.mjs ./
ADD https://github.com/awslabs/llrt/releases/latest/download/llrt-container-arm64 /usr/bin/llrt
RUN chmod +x /usr/bin/llrt

ENV LAMBDA_HANDLER "app.handler"

CMD [ "llrt" ]
```

The image copies app.mjs into /var/task, pulls the arm64 container build of the runtime, sets LAMBDA_HANDLER to app.handler and starts llrt as the entrypoint. Options 4 and 5 cover AWS SAM and AWS CDK. The CDK path uses a third party construct library, cdk-lambda-llrt, which the README shows like this:

```ts
import { LlrtFunction } from "cdk-lambda-llrt";

const handler = new LlrtFunction(this, "Handler", {
  entry: "lambda/index.ts",
});
```

Before any of that, the practical first step is compatibility testing. LLRT ships a test runner with a lightweight Jest-like API that supports Jest and Chai assertions. Running llrt test scans the current directory and subdirectories for files ending in *.test.js or *.test.mjs. A specific directory can be passed with llrt test -d <directory>, and extra arguments act as filters, so llrt test crypto runs only tests whose filename contains crypto.

```bash
llrt test
llrt test -d ./tests
llrt test crypto
```

If your existing suite passes under that runner, you have evidence the handler is a candidate. If it fails on a module the matrix marks unsupported, you have your answer sooner and cheaper than after a deployment.

## Bundling rules and the Node.js gap

The README is explicit that LLRT supports ES2023 but is not a drop in replacement for Node.js, and adds that it never will be. Two bundling constraints follow from that. All dependencies should be bundled for a browser platform, and included @aws-sdk packages should be marked external. Bundling for the browser is what strips the Node.js built-ins LLRT does not implement; marking the AWS SDK external is what lets the runtime supply its own SDK implementation instead of shipping the full one.

This is the part of the project that will cost the most engineering time. A handler that imports a library which transitively pulls in node:http will not bundle cleanly for the browser, and node:http is unsupported in LLRT. The failure surfaces at bundle time or at first invocation, not at code review.

The test story has three layers, and the README describes what each is for. Unit tests validate specific modules and functions in isolation. End-to-end tests validate compatibility with the AWS SDK and WinterTC compliance. Web Platform Tests validate behavior against standardized browser APIs. The e2e and WPT suites have their own README files under tests/e2e and tests/wpt. All three exist because the runtime is not simply Node.js with a faster engine.

## Where LLRT is the wrong tool

Any function that depends on node:cluster, node:dgram, node:http2, node:inspector or node:diagnostics_channel cannot run on LLRT as documented. That rules out HTTP servers built on the node:http module, WebSocket servers, UDP workloads, and anything that relies on the Node inspector for in-process debugging. The absence of node:inspector is a real operational cost: the debugging workflow you use today for a Node.js Lambda does not transfer.

The partial support column is subtler. When node:crypto or node:fs is marked as supported with a warning, the matrix is telling you the module exists but does not cover the whole Node.js surface. The README defers detail to API.md, which is the file you should read before assuming a specific function is present. A handler that uses three functions from node:fs may be fine; one that uses thirty may not be.

The experimental warning is not boilerplate. The version numbers in this repository are all beta: v0.9.0-beta, v0.8.1-beta and v0.8.0-beta. The root package.json still carries version 0.5.1-beta, which suggests the workspace manifest and the release tags are not kept in lockstep. For a production system with a long support horizon, that is a signal to wait rather than a reason to dismiss the project.

## LLRT against Node.js and Bun on Lambda

The meaningful comparison is not LLRT versus Node.js in general, it is LLRT versus the runtime you would otherwise deploy on Lambda. Node.js on Lambda has full API coverage and a mature debugging and observability story, at the cost of slower initialization. LLRT trades that coverage for startup time. The trade is only worth making when the handler is small, the dependency graph is browser-bundleable, and cold start latency is the metric that matters.

Bun is the other JavaScript runtime that comes up in this context, and the difference in approach is architectural. Bun is a general purpose runtime with a broad Node.js compatibility goal and its own package manager and bundler. LLRT is scoped to Lambda, uses QuickJS rather than JavaScriptCore, and explicitly disclaims the goal of full Node.js compatibility. If your workload is a long running server or a CLI, Bun is the more plausible choice; LLRT is not designed for either.

For teams already on AWS CDK, the cdk-lambda-llrt construct is the lowest friction entry point because it wraps the packaging steps. Teams on SAM have the example project under example/llrt-sam, and container image users have example/llrt-sam-container-image. The repository also ships a benchmarks directory and an example/functions directory whose v3-lib.mjs is the DynamoDB Put function used in the README's benchmark images.

## Licence, releases and upgrade cost

LLRT is Apache-2.0, both in the repository metadata and in the root package.json. The repository also carries a NOTICE file and a THIRD_PARTY_LICENSES file, which matters because the runtime bundles QuickJS and other components. If you redistribute LLRT inside a container image or a Lambda layer, read those two files rather than assuming the Apache-2.0 header covers everything. That is a packaging question, not a legal opinion, and it is worth a look from whoever owns your licence compliance.

The upgrade cost is tied to the beta cadence. Releases are tagged as betas, so a version bump can change runtime behavior. The compatibility matrix and API.md are the documents that tell you what moved. The Makefile pins a specific Rust nightly toolchain, which means building from source is reproducible only against that pinned version. If you consume prebuilt release artifacts instead, you avoid that constraint but inherit whatever the release was built with.

The last push to the repository was on 2026-09-20, and the most recent release, v0.9.0-beta, was tagged on 2026-09-06. The project is not archived.

## Conclusion

Adopt LLRT only for small Lambda handlers that are already bundled for the browser platform and whose dependencies do not reach for node:cluster, node:dgram, node:http2 or node:inspector. Do not adopt it as a general Node.js runtime, and do not expect a drop-in migration: the compatibility matrix marks most supported modules as partial. Before committing, run your existing test suite under llrt test, then package the bootstrap binary as a custom runtime on Amazon Linux 2023 and compare the cold start against your current Node.js deployment.

## FAQ

### What is LLRT?

LLRT (Low Latency Runtime) is an experimental, lightweight JavaScript runtime from AWS Labs designed for serverless applications. It is built in Rust and uses QuickJS as its JavaScript engine, and the README states it offers up to over 10x faster startup than other JavaScript runtimes on AWS Lambda.

### What is cold start in AWS Lambda, and why does LLRT target it?

The README frames LLRT around startup latency for Lambda functions and measures its HTTP benchmarks in round trip time for a cold start. It claims up to over 10x faster startup and up to 2x overall lower cost compared to other JavaScript runtimes on AWS Lambda, with a link to its benchmark methodology.

### How do I install LLRT for a Lambda function?

Download the last LLRT release from the GitHub releases page. The README lists five options: a custom runtime on Amazon Linux 2023 with the bootstrap binary (recommended), an uploaded layer using llrt-lambda-arm64.zip or llrt-lambda-x64.zip, a container image, AWS SAM, or the cdk-lambda-llrt construct library.

### Is LLRT a drop-in replacement for Node.js?

No. The README states it is not a drop in replacement for Node.js and adds that it never will be. The compatibility matrix marks many modules as partially supported and lists node:cluster, node:dgram, node:http2 and node:inspector as unsupported.

### How do I test whether my code works on LLRT?

Use the built-in test runner, which supports Jest and Chai assertions. Running llrt test scans the current directory and subdirectories for files ending in *.test.js or *.test.mjs, llrt test -d <directory> scans a specific directory, and extra arguments filter by filename.

### What licence does LLRT use?

LLRT is licensed under Apache-2.0, as stated in the repository metadata and the root package.json. The repository also includes NOTICE and THIRD_PARTY_LICENSES files covering bundled components.

## Sources

- [awslabs/llrt on GitHub](https://github.com/awslabs/llrt)
- [Issues](https://github.com/awslabs/llrt/issues)
- [License: Apache-2.0](https://github.com/awslabs/llrt/blob/main/LICENSE)
- [README](https://github.com/awslabs/llrt/blob/main/README.md)
- [Releases](https://github.com/awslabs/llrt/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/awslabs-llrt
