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

# Serverless

> Flush buffered events before your function exits so nothing is lost on serverless and other short-lived runtimes.

Carbon captures events into an in-memory buffer and delivers them in the background, so instrumentation never blocks your request path. On a long-running server that buffer drains on its own. On serverless platforms — Next.js route handlers, Vercel Functions, AWS Lambda, Cloudflare Workers — the runtime freezes or tears down the moment your handler returns, so any events still in the buffer never get sent.

The fix is one line: drain the buffer before the function exits.

```typescript theme={null}
await carbon.flushPendingEvents();
```

`flushPendingEvents` resolves once every buffered event is either delivered or deliberately dropped (and reported through [`onError`](/documentation/sdk/configuration#delivery-errors)). It rejects only when a transient delivery failure leaves events buffered, so you can decide how to handle loss at shutdown:

```typescript theme={null}
try {
  await carbon.flushPendingEvents();
} catch (error) {
  console.error("Carbon flush failed", error);
}
```

<Note>
  Create the `Carbon` instance and wrap your client once at module scope, not
  per request — the buffer and its background delivery are shared across the
  warm invocations that reuse the same instance.
</Note>

## Flush after the response

Awaiting the flush before you return delays the response by however long delivery takes. On platforms that can keep the function alive past the response, schedule the flush as post-response work instead — the user gets their response immediately and events still drain before the runtime freezes.

<Tabs>
  <Tab title="Next.js">
    Next.js `after` runs a callback once the response has finished streaming, without blocking it:

    ```typescript theme={null}
    import { after } from "next/server";

    export async function POST(req: Request) {
      const completion = await openai.chat.completions.create({
        model: "gpt-5.4-nano",
        messages: [{ role: "user", content: await req.text() }],
      });

      after(() => carbon.flushPendingEvents());

      return Response.json(completion);
    }
    ```
  </Tab>

  <Tab title="Vercel Functions">
    `waitUntil` extends the function's lifetime until the promise settles:

    ```typescript theme={null}
    import { waitUntil } from "@vercel/functions";

    export async function POST(req: Request) {
      const completion = await openai.chat.completions.create({
        model: "gpt-5.4-nano",
        messages: [{ role: "user", content: await req.text() }],
      });

      waitUntil(carbon.flushPendingEvents());

      return Response.json(completion);
    }
    ```
  </Tab>

  <Tab title="AWS Lambda">
    Await the flush before returning — Lambda freezes the execution environment as soon as the handler resolves:

    ```typescript theme={null}
    export const handler = async (event) => {
      const completion = await openai.chat.completions.create({
        model: "gpt-5.4-nano",
        messages: [{ role: "user", content: event.body }],
      });

      await carbon.flushPendingEvents();

      return { statusCode: 200, body: JSON.stringify(completion) };
    };
    ```
  </Tab>

  <Tab title="Cloudflare Workers">
    Hand the flush to `ctx.waitUntil` so it runs after the response is returned:

    ```typescript theme={null}
    export default {
      async fetch(req, env, ctx) {
        const completion = await openai.chat.completions.create({
          model: "gpt-5.4-nano",
          messages: [{ role: "user", content: await req.text() }],
        });

        ctx.waitUntil(carbon.flushPendingEvents());

        return Response.json(completion);
      },
    };
    ```
  </Tab>
</Tabs>

<Warning>
  Background work scheduled with `after`, `waitUntil`, or `ctx.waitUntil` is
  best-effort. If the platform terminates the instance early — a hard timeout,
  for example — the flush may not finish. Await the flush directly when you
  cannot tolerate any loss.
</Warning>

## Why an explicit flush is needed

By default a buffered batch is sent when it reaches 50 events or after it has waited 5 seconds, whichever comes first. A serverless invocation usually handles a single request and returns in well under 5 seconds, so neither threshold is reached before the runtime freezes — the explicit flush is what forces delivery.

You can tune these thresholds — `bufferBatchSize`, `bufferMaxTimeMs`, and the rest — but in a short-lived function flushing before exit is the reliable guarantee. See [Configuration](/documentation/sdk/configuration#buffering-and-flushing) for the full set of buffering options and delivery semantics.

## Long-running servers

Persistent processes — a Node server, a container — drain the buffer continuously as it fills, so no per-request flush is needed. Call `flushPendingEvents` only on graceful shutdown, so events captured just before exit are delivered:

```typescript theme={null}
process.on("SIGTERM", async () => {
  await carbon.flushPendingEvents();
  process.exit(0);
});
```
