- Add support for file types Bun doesn’t handle natively (
.scss,.yaml,.svg, etc.) - Implement custom module resolution rules
- Inject code or environment data as virtual modules
- Apply framework-level transforms like CSS extraction or macros
Creating a plugin
A plugin is a plain object with aname string and a setup function. The setup function receives a build object with lifecycle hook registration methods.
my-plugin.ts
Using a plugin at runtime
To apply a plugin when running code withbun run, use Bun.plugin() in a preload file and register that file in bunfig.toml.
1
Define the plugin
my-plugin.ts
2
Register as a preload in bunfig.toml
bunfig.toml
3
Import the custom file type
index.ts
Using a plugin in the bundler
Pass the plugin toBun.build via the plugins array.
build.ts
Lifecycle hooks
onLoad
onLoad intercepts a module after it has been resolved and lets you replace its contents before Bun parses it.
filter regex is matched against the file path. Return contents (a string) and optionally a loader to tell Bun how to interpret the content.
Example: virtual environment module
.txt files as strings
.defer()
The second argument to onLoad is a defer function. Calling await defer() pauses execution of this callback until all other modules have been loaded. This is useful when a module’s content depends on what other modules export.
onResolve
onResolve intercepts module resolution and lets you redirect imports to different paths.
onStart
onStart registers a callback that runs once when the bundler starts. It can be async; the bundler waits for all onStart callbacks to resolve before continuing.
onStart callbacks cannot modify build.config. To mutate the build config, do so directly inside setup() before registering any hooks.Available loaders
Theloader field in an onLoad return value tells Bun how to parse the returned contents.
Namespaces
Every module has a namespace. The default namespace is"file". Namespaces are used to prefix module paths in transpiled code.
onLoad or onResolve scopes the hook to only matching modules:
Native plugins
JavaScript plugins run on a single thread. For maximum performance, you can write a native plugin as a Node-API (NAPI) module. Native plugins run on multiple threads and avoid UTF-8 to UTF-16 conversion overhead.onBeforeParse
The onBeforeParse hook is the only lifecycle hook available to native plugins. It runs immediately before a file is parsed, on any thread, and can replace the file’s source code.
onBeforeParse signature. Here is an example in Rust using the bun-native-plugin crate:
lib.rs