
Last year we added support for Bun as a package manager for Pulumi TypeScript projects. Today we’re taking the next step: Bun is now a fully supported runtime for Pulumi programs. Set runtime: bun in your Pulumi.yaml and Bun will execute your entire Pulumi program, with no Node.js required. Since Bun’s 1.0 release, this has been one of our most requested features.
Bun is a JavaScript runtime designed as an all-in-one toolkit: runtime, package manager, bundler, and test runner. For Pulumi users, the most relevant advantages are:
Native TypeScript support: Bun runs TypeScript directly without requiring ts-node or a separate compile step.
Fast package management: Bun’s built-in package manager can install dependencies significantly faster than npm.
Node.js compatibility: Bun aims for 100% Node.js compatibility, so the npm packages you already use with Pulumi should work out of the box.
With runtime: bun, Pulumi uses Bun for both running your program and managing your packages, giving you a streamlined single-tool experience.
To create a new Pulumi project with the Bun runtime, run:
pulumi new bun
This creates a TypeScript project configured to use Bun. The generated Pulumi.yaml looks like this:
name: my-bun-project
runtime: bun
From here, write your Pulumi program as usual. For example, to create a random password using the @pulumi/random package:
bun add @pulumi/random
import * as random from "@pulumi/random";
const password = new random.RandomPassword("password", {
length: 20,
});
export const pw = password.result;
Then deploy with:
pulumi up
Prerequisites:
If you have an existing Pulumi TypeScript project running on Node.js, you can convert it to use the Bun runtime in a few steps.
Pulumi.yamlChange the runtime field from nodejs to bun:
Before:
runtime:
name: nodejs
options:
packagemanager: npm
After:
runtime: bun
**
When the runtime is set to bun, Bun is also used as the package manager — there’s no need to configure a separate packagemanager option.
tsconfig.jsonBun handles TypeScript differently from Node.js with ts-node. Update your tsconfig.json to use Bun’s recommended compiler options:
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"moduleResolution": "bundler",
"allowJs": true,
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}
Key differences from a typical Node.js tsconfig.json:
module: "Preserve" and moduleResolution: "bundler": Let Bun handle module resolution instead of compiling to CommonJS. The bundler resolution strategy allows extensionless imports while still respecting package.json exports, matching how Bun resolves modules in practice.
verbatimModuleSyntax: true: Enforces consistent use of ESM import/export syntax. TypeScript will flag any remaining CommonJS patterns like require() at compile time.
Bun makes it easy to go full ESM and it’s the recommended module format for Bun projects. Add "type": "module" to your package.json:
{
"type": "module"
}
With ECMAScript module (ESM) syntax, one thing that gets easier is working with async code. In a CommonJS Pulumi program, if you need to await a data source or other async call before declaring resources, the program must be wrapped in an async entrypoint function. With ESM and Bun, top-level await just works, so you can skip the wrapper function entirely and await directly at the module level:
import * as aws from "@pulumi/aws";
const azs = await aws.getAvailabilityZones({ state: "available" });
const buckets = azs.names.map(az => new aws.s3.BucketV2(`my-bucket-${az}`));
export const bucketNames = buckets.map(b => b.id);
If your existing program does use an async entrypoint with export =, just replace it with the ESM-standard export default:
// CommonJS (Node.js default)
export = async () => {
const bucket = new aws.s3.BucketV2("my-bucket");
return { bucketName: bucket.id };
};
// ESM (used with Bun)
export default async () => {
const bucket = new aws.s3.BucketV2("my-bucket");
return { bucketName: bucket.id };
};
Make sure you’re running @pulumi/pulumi version 3.226.0 or later:
bun add @pulumi/pulumi@latest
pulumi install
pulumi up
With this release, there are now two ways to use Bun with Pulumi:
Configuration Bun’s role Node.js required?
runtime: bun
Runs your program and manages packages
No
runtime: { name: nodejs, options: { packagemanager: bun } }
Manages packages only
Yes
Use runtime: bun for the full Bun experience. The package-manager-only mode is still available for projects that need Node.js-specific features like function serialization.
The following Pulumi features are not currently supported when using the Bun runtime:
**
Callback functions (magic lambdas) are not supported. APIs like aws.lambda.CallbackFunction and event handler shortcuts (e.g., bucket.onObjectCreated) use function serialization which requires Node.js v8 and inspector modules that are only partially supported in Bun.
Dynamic providers are not supported. Dynamic providers (pulumi.dynamic.Resource) similarly rely on function serialization.
If your project uses any of these features, continue using runtime: nodejs. You can still benefit from Bun’s fast package management by setting packagemanager: bun in your runtime options.
Bun runtime support is available now in Pulumi 3.227.0. To get started:
Create a new project: pulumi new bun
Read the docs: TypeScript (Node.js) SDK
Report issues or share feedback on GitHub or in the Pulumi Community Slack
Thank you to everyone who upvoted, commented on, and contributed to the original feature request. Your feedback helped shape this feature, and we’d love to hear how it works for you.
Fetched April 11, 2026