> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bun

> This guide explains how to deploy a basic Bun site to Sevalla.

[Bun](https://bun.com/) is a fast, modern JavaScript runtime built with Zig and powered by the JavaScriptCore engine. It focuses on high performance, offering quick startup times, fast package installs, and a built-in HTTP server. Bun includes a package manager, bundler, test runner, and TypeScript/JSX transpiler out of the box, providing an all-in-one environment for building JavaScript applications.

Key features include:

* Native Bun HTTP server using `Bun.serve()` .
* No build step required - TypeScript runs directly.
* Built-in TypeScript support - No transpilation needed.
* Fast startup - Instant server boot.
* Minimal dependencies - Only `@types/bun` for development.
* Health check endpoint included.

Bun can only be used on Application Hosting; it cannot be deployed as a static site.

## Configuration

With Bun, no build step is required. Bun runs TypeScript directly, so you don't need a separate build command. Sevalla will automatically:

1. Run `bun install` to install dependencies.
2. Execute `bun run start` to start your server.

The following is an example `package.json` file for deploying Bun on Sevalla:

```json theme={null}
{
  "scripts": {
    "start": "bun run src/index.ts"
  }
}
```

## Containerization

### Dockerfile

The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The Dockerfile below follows best practices for building and running a Bun application in Sevalla. It:

* Uses official `oven/bun` image for optimal performance.
* Installs dependencies with `--frozen-lockfile` for deterministic builds.
* Exposes port 3000 by default.
* Runs the application using `bun run start` .
* Excludes unnecessary files via `.dockerignore` (node\_modules, .git, .env, etc.).

```javascript theme={null}
FROM oven/bun

WORKDIR /app

COPY package.json ./

RUN bun install --frozen-lockfile

COPY . .

EXPOSE 3000

ENV PORT=3000

CMD ["bun", "run", "start"]
```

### Nixpacks

[**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) detects Bun projects automatically by locating a `package.json` and `bun.lock` file in your application. It then installs the Bun runtime, runs `bun install` to fetch dependencies, and uses the `start` script from your `package.json` file to configure how your application is launched.

<Warning>
  You must use **Nixpacks v1.39** or newer for proper Bun support. You can set the Nixpacks version within **Applications** > ***Application name*** > **Settings** > **Update build strategy**.
</Warning>

When using Nixpacks in Sevalla for your Bun application:

* Ensure your `package.json` has a valid `start` script.
* Nixpacks respects your `bun.lock` file for deterministic builds.
* All standard Sevalla features (CDN, scaling, processes) work with Nixpacks.
* Nixpacks uses Node 18 by default, but Bun requires Node 22. To ensure compatibility, set the `NIXPACKS_NODE_VERSION` environment variable to `22`.

## CDN

Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Bun application, we recommend the following best practices:

* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Use versioned URLs for static assets (e.g., `/static/app.v123.js`).

### Optimizing Bun server for CDN

#### Static files with cache headers

```javascript theme={null}
// src/index.ts
const server = Bun.serve({
  port: process.env.PORT || 3000,
  fetch(req) {
    const url = new URL(req.url);

    // Serve static assets with caching
    if (url.pathname.startsWith("/static/")) {
      const file = Bun.file(`./public${url.pathname}`);

      return new Response(file, {
        headers: {
          "Cache-Control": "public, max-age=31536000, immutable",
          "Content-Type": file.type,
        },
      });
    }

    // API endpoint with shorter cache
    if (url.pathname === "/api/data") {
      const data = { message: "Hello from Bun!" };

      return new Response(JSON.stringify(data), {
        headers: {
          "Content-Type": "application/json",
          "Cache-Control": "public, max-age=3600, s-maxage=3600",
        },
      });
    }

    return new Response("Not Found", { status: 404 });
  },
});
```

## Edge caching

[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Bun application, we recommend the following best practices:

* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.

### Optimizing Bun for edge caching

```javascript theme={null}
// src/index.ts
const server = Bun.serve({
  port: process.env.PORT || 3000,
  fetch(req) {
    const url = new URL(req.url);

    // API with edge caching
    if (url.pathname === "/api/products") {
      const products = getProducts(); // Your data fetching logic

      return new Response(JSON.stringify(products), {
        headers: {
          "Content-Type": "application/json",
          "Cache-Control": "public, max-age=60, s-maxage=3600",
        },
      });
    }

    // User-specific data (don't cache)
    if (url.pathname === "/api/user/profile") {
      return new Response(JSON.stringify({ user: "data" }), {
        headers: {
          "Content-Type": "application/json",
          "Cache-Control": "private, no-cache",
        },
      });
    }

    return new Response("Not Found", { status: 404 });
  },
});
```

### `Cache-Control`

With Sevalla’s Cloudflare integration, `Cache-Control` headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Bun application:

* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.

<Info>
  Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
</Info>

## Health checks

Ensure your application remains available during deployments by implementing health checks:

* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.

### Basic healthcheck

```javascript theme={null}
// src/index.ts
const server = Bun.serve({
  port: process.env.PORT || 3000,
  fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/api/health") {
      return new Response(
        JSON.stringify({
          status: "ok",
          timestamp: new Date().toISOString(),
          runtime: "Bun",
          version: Bun.version,
        }),
        {
          headers: { "Content-Type": "application/json" },
        }
      );
    }

    return new Response("Not Found", { status: 404 });
  },
});
```

## Graceful shutdown

Bun supports graceful shutdown by default. For custom cleanup logic, use `SIGTERM` and `SIGINT` , for example:

```javascript theme={null}
// src/index.ts
import { pool } from "./lib/db";

const server = Bun.serve({
  port: process.env.PORT || 3000,
  fetch(req) {
    // ... your routes
  },
});

// Graceful shutdown
process.on("SIGTERM", async () => {
  console.log("Received SIGTERM, closing connections...");

  // Close database pool
  await pool.end();

  // Stop server
  server.stop();

  console.log("Server closed gracefully");
  process.exit(0);
});

process.on("SIGINT", async () => {
  console.log("Received SIGINT, closing connections...");
  await pool.end();
  server.stop();
  process.exit(0);
});
```

## S3

Bun includes a [built-in s3 package](https://bun.com/docs/runtime/s3) that integrates seamlessly with Sevalla's [object storage](https://docs.sevalla.com/object-storage/overview).

You can also integrate your Bun application with AWS S3 for object storage, file uploads, and static assets.

### Set up AWS S3

1. **Install AWS SDK dependency:**

```javascript theme={null}
bun add @aws-sdk/client-s3
```

2. **Set S3 environment variables:**

```javascript theme={null}
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your_access_key_here
S3_SECRET_ACCESS_KEY=your_secret_key_here
S3_ENDPOINT=https://s3.sevalla.com
S3_BUCKET_NAME=your_bucket_name
```

For production, use your Sevalla S3 service credentials or external S3-compatible provider (AWS S3, Cloudflare R2, MinIO, etc.)

### AWS S3 Usage

The S3 client is initialized in `src/s3.ts`:

```javascript theme={null}
import { S3Client } from "@aws-sdk/client-s3";

const s3Client = new S3Client({
  region: process.env.S3_REGION || "us-east-1",
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
  },
  endpoint: process.env.S3_ENDPOINT,
});

export default s3Client;
```
