Core toolchainRuntime

Runtime

Run TypeScript, execute scripts, read environment variables, and serve HTTP

Last updated on

When to use it

Use the Bun runtime when the goal is to execute JavaScript or TypeScript, rather than install dependencies, run tests, or emit a bundle.

bun run index.ts
bun index.ts          # shorthand
bun run dev           # package.json script
bun --watch index.ts  # restart on file changes
bun --hot index.ts    # hot reload with state preservation where possible

TypeScript and modules

Bun parses .ts, .tsx, JSX, and common ESM/CommonJS patterns. Execution strips types; static checking remains a TypeScript job:

bun add -d typescript
bunx tsc --noEmit

Environment variables

Bun automatically reads common .env files. Use process.env or Bun.env, and validate required values at startup:

const port = Number(Bun.env.PORT ?? 3000);
const apiKey = Bun.env.API_KEY;

if (!apiKey) throw new Error('API_KEY is required');

Never put server secrets into source, logs, untrusted agent context, or browser bundles.

HTTP server

const server = Bun.serve({
  port: Number(Bun.env.PORT ?? 3000),
  routes: {
    '/health': () => Response.json({ ok: true }),
    '/users/:id': (req) => Response.json({ id: req.params.id }),
  },
  fetch() {
    return new Response('Not found', { status: 404 });
  },
});

console.log(server.url.href);

Common runtime APIs

GoalAPIBoundary
FilesBun.file() / Bun.write()Bun.file() returns a lazy Blob-like value
HTTPBun.serve()Uses standard Request and Response
ProcessesBun.spawn() / Bun.spawnSync()Prefer argument arrays for untrusted input
PasswordsBun.passwordDo not substitute a general fast hash
SQLitebun:sqliteYou still own migrations and resource lifetime
SQLBun.SQLPostgreSQL, MySQL, and SQLite; budget pools and own migrations
RedisRedisClientCurrently requires Redis 7.2+; close long-lived connections
Object storageS3ClientS3-compatible services; provider policy still applies
ShellBun.$Keep command structure trusted; never interpolate unchecked input

See Data and storage for database, cache, and object-storage boundaries.

Graceful shutdown

const server = Bun.serve({ fetch: () => new Response('ok') });

async function shutdown() {
  await server.stop();
  process.exit(0);
}

process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);

A production service should also drain databases and queues with a bounded timeout.

Cloud boundaries

  • Bun.serve honors PORT, or you can set port; do not hard-code a port when the container platform injects one.
  • It listens on all interfaces by default. Use platform network policy, a reverse proxy, and application authentication to control access.
  • The default idle timeout is 10 seconds. Evaluate idleTimeout for AI streams or long requests and, when appropriate, use server.timeout(request, 0) for a specific request while retaining application-level cancellation and total timeouts.
  • Set maxRequestBodySize; do not buffer unbounded uploads in memory.

Official references: Runtime, HTTP server, and Bun APIs.