Runtime APIs

Use Node.js packages with clear boundaries

Run Node.js APIs and npm packages in Bun while identifying the compatibility assumptions your application depends on.

8 minute lesson

~~~

Bun implements many Node.js built-in modules. Use the explicit node: prefix when importing one:

import { join } from 'node:path'

const file = join('data', 'notes.json')
console.log(file)

This code runs in Bun and Node.js. The prefix also tells the reader that path comes from the runtime, not node_modules.

Most npm packages install normally:

bun add zod

Then import them with standard ES module syntax:

import { z } from 'zod'

const Note = z.object({
  title: z.string().min(1),
})

console.log(Note.parse({ title: 'Learn Bun' }))

Compatibility needs evidence

A successful installation only proves the package was downloaded. Run the paths your application uses.

Pay extra attention when a dependency uses:

  • a native Node.js add-on
  • a recently added Node.js API
  • Node.js internals rather than public APIs
  • process, stream, or module behavior at the edges

Check Bun’s Node.js compatibility documentation when something fails. Then create a small reproduction before changing the application.

You can detect Bun at runtime with:

if (process.versions.bun) {
  console.log(`Running Bun ${process.versions.bun}`)
}

Use runtime checks only when behavior must differ. Shared Web APIs such as Request, Response, fetch, and URL usually create a cleaner boundary than many Bun-versus-Node branches.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →