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

# Bun

> Step-by-step Bun rate limiting tutorial using @unkey/ratelimit. Build a Bun HTTP server that throttles abusive clients with no Redis required.

## What you'll build

A Bun HTTP server with rate limiting. Users who exceed the limit get a 429 response.

**Time to complete:** \~3 minutes

## Prerequisites

* [Unkey account](https://app.unkey.com/auth/sign-up) (free)
* [Root key](https://app.unkey.com/settings/root-keys) with `ratelimit.*.limit` permission
* [Bun](https://bun.sh) installed

<Steps titleSize="h3">
  <Step title="Create a Bun project">
    ```bash theme={"theme":"kanagawa-wave"}
    mkdir unkey-bun-ratelimit && cd unkey-bun-ratelimit
    bun init -y
    ```
  </Step>

  <Step title="Install the SDK">
    ```bash theme={"theme":"kanagawa-wave"}
    bun add @unkey/ratelimit
    ```
  </Step>

  <Step title="Add your root key">
    Create a `.env` file:

    ```bash .env theme={"theme":"kanagawa-wave"}
    UNKEY_ROOT_KEY="unkey_..."
    ```
  </Step>

  <Step title="Create your server">
    Replace `index.ts`:

    ```ts index.ts theme={"theme":"kanagawa-wave"}
    import { Ratelimit } from "@unkey/ratelimit";

    // Create limiter instance
    const limiter = new Ratelimit({
      rootKey: Bun.env.UNKEY_ROOT_KEY!,
      namespace: "bun-api",
      limit: 10, // 10 requests...
      duration: "60s", // ...per minute
    });

    const server = Bun.serve({
      async fetch(req) {
        const url = new URL(req.url);

        // Public route
        if (url.pathname === "/") {
          return Response.json({ message: "Welcome! Try /api/data" });
        }

        // Rate-limited route
        if (url.pathname === "/api/data") {
          // 1. Identify the user
          const identifier =
            req.headers.get("x-user-id") ??
            req.headers.get("x-forwarded-for") ??
            "anonymous";

          // 2. Check the rate limit
          const { success, remaining, reset } = await limiter.limit(identifier);

          // 3. Set headers
          const headers = {
            "X-RateLimit-Limit": "10",
            "X-RateLimit-Remaining": remaining.toString(),
            "X-RateLimit-Reset": reset.toString(),
          };

          if (!success) {
            return Response.json(
              { error: "Too many requests. Try again later." },
              { status: 429, headers },
            );
          }

          // 4. Request allowed
          return Response.json(
            { message: "Here's your data!", remaining },
            { headers },
          );
        }

        return Response.json({ error: "Not found" }, { status: 404 });
      },
      port: 3000,
    });

    console.log(`Server running at http://localhost:${server.port}`);
    ```
  </Step>

  <Step title="Run your server">
    ```bash theme={"theme":"kanagawa-wave"}
    bun run index.ts
    ```
  </Step>

  <Step title="Test it">
    ```bash theme={"theme":"kanagawa-wave"}
    # Hit the endpoint 12 times
    for i in {1..12}; do
      curl http://localhost:3000/api/data -H "x-user-id: test-user"
      echo ""
    done
    ```

    First 10 requests return data. Requests 11+ get:

    ```json theme={"theme":"kanagawa-wave"}
    { "error": "Too many requests. Try again later." }
    ```
  </Step>
</Steps>

## What's in the response?

`limiter.limit()` returns:

| Field       | Type      | Description                                |
| ----------- | --------- | ------------------------------------------ |
| `success`   | `boolean` | `true` if allowed, `false` if rate limited |
| `remaining` | `number`  | Requests left in current window            |
| `reset`     | `number`  | Unix timestamp (ms) when window resets     |
| `limit`     | `number`  | The configured limit                       |

## Multiple rate limiters

Create different limiters for different use cases:

```ts index.ts theme={"theme":"kanagawa-wave"}
import { Ratelimit } from "@unkey/ratelimit";

// General API: 100/min
const apiLimiter = new Ratelimit({
  rootKey: Bun.env.UNKEY_ROOT_KEY!,
  namespace: "api",
  limit: 100,
  duration: "60s",
});

// Auth endpoints: 5/min (prevent brute force)
const authLimiter = new Ratelimit({
  rootKey: Bun.env.UNKEY_ROOT_KEY!,
  namespace: "auth",
  limit: 5,
  duration: "60s",
});

// Helper to apply rate limiting
async function checkLimit(limiter: Ratelimit, identifier: string) {
  const result = await limiter.limit(identifier);
  if (!result.success) {
    return Response.json({ error: "Rate limit exceeded" }, { status: 429 });
  }
  return null; // Allowed
}

const server = Bun.serve({
  async fetch(req) {
    const url = new URL(req.url);
    const ip = req.headers.get("x-forwarded-for") ?? "unknown";

    if (url.pathname === "/api/login") {
      const blocked = await checkLimit(authLimiter, ip);
      if (blocked) return blocked;

      return Response.json({ message: "Login endpoint" });
    }

    if (url.pathname.startsWith("/api/")) {
      const blocked = await checkLimit(apiLimiter, ip);
      if (blocked) return blocked;

      return Response.json({ message: "API data" });
    }

    return Response.json({ message: "Welcome" });
  },
  port: 3000,
});
```

## Next steps

<CardGroup cols={2}>
  <Card title="How it works" icon="bolt" href="/platform/ratelimiting/how-it-works">
    Understand the architecture
  </Card>

  <Card title="Per-user overrides" icon="sliders" href="/platform/ratelimiting/overrides">
    Give specific users higher limits
  </Card>

  <Card title="SDK Reference" icon="book" href="/libraries/ts/ratelimit/ratelimit">
    All configuration options
  </Card>

  <Card title="Add API key auth" icon="key" href="/quickstart/apis/bun">
    Combine with API key authentication
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Rate limit not applying?">
    * Verify `UNKEY_ROOT_KEY` is in your `.env` file - Use
      `Bun.env.UNKEY_ROOT_KEY` (not `process.env`) - Check your root key has
      `ratelimit.*.limit` permission
  </Accordion>

  <Accordion title="Environment not loading?">
    Bun loads `.env` automatically. Make sure the file is in your project root
    and restart the server.
  </Accordion>
</AccordionGroup>
