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

# Serverless and short-lived processes

> Export reliably from lambdas, edge handlers, Cloudflare Workers, CLIs, and jobs.

Spans buffer in a background batch by default — 64 spans or a five-second
interval, whichever comes first. A process that exits, or a function instance
that freezes, before that batch exports **loses those spans**.

This page is TypeScript-specific. Python services are long-lived in practice;
for a Python script or job, call `client.flush()` in a `finally` block.

## Export per span instead of batching

`exportMode: "immediate"` replaces the batcher with per-span export. Use it
whenever the process lifetime is one request.

```typescript theme={null}
const client = atlan.init({
  serviceName: "support-rover",
  apiKey: env.ATLAN_API_KEY,
  workspaceId: env.ATLAN_WORKSPACE_ID,
  exportMode: "immediate",
});
```

Still call `flush()` before returning — the export itself is asynchronous.
`ATLAN_DEBUG=true` forces immediate mode as well, which is why debug runs
surface a rejected export straight away.

## Keep the instance alive with waitUntil

`waitUntil` hands every background flush promise to the platform, so the
runtime keeps the instance alive until export finishes instead of freezing it
mid-request.

```typescript theme={null}
export default {
  async fetch(request, env, ctx) {
    const client = atlan.init({
      serviceName: "support-rover",
      apiKey: env.ATLAN_API_KEY,
      workspaceId: env.ATLAN_WORKSPACE_ID,
      exportMode: "immediate",
      waitUntil: (promise) => ctx.waitUntil(promise),
    });

    const response = await handle(request);
    void client.flush(); // rides ctx.waitUntil; no need to block the response
    return response;
  },
};
```

On Vercel's Node runtime, use `after` from `next/server`:

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

after(() => client.flush());
```

<Note>
  Cloudflare Workers have no ambient environment, so `ATLAN_*` variables are
  not readable. Pass `apiKey`, `workspaceId`, and everything else through
  `init()` from the Worker's `env` binding.
</Note>

## CLIs and jobs

Node runs a best-effort flush on `beforeExit`, but being explicit is reliable:

```typescript theme={null}
try {
  await runJob();
} finally {
  await client.flush(); // or client.shutdown() on final exit
}
```

## Bundling for Cloudflare Workers

Wrangler users get what they need from `compatibility_flags = ["nodejs_compat"]`
with a recent `compatibility_date`.

For a direct esbuild bundle, this is the supported configuration — it matches
the SDK's own Workers smoke test:

```bash theme={null}
esbuild worker.mjs --bundle --format=esm --platform=node \
  --main-fields=module,main \
  --conditions=workerd,module,import \
  --banner:js='import { createRequire as __cr } from "node:module"; var require = __cr(import.meta?.url ?? "file:///worker.mjs");'
```

Each flag is load-bearing:

| Flag                                 | Why                                                                                                                                                               |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--platform=node`                    | Auto-externalizes Node builtins, which `nodejs_compat` provides at runtime.                                                                                       |
| `--conditions=workerd,module,import` | Custom conditions drop esbuild's implicit `module` condition. Without adding it back, the OTel packages resolve to CJS whose top-level evaluation breaks Workers. |
| `--main-fields=module,main`          | Some OTel packages have no `exports` map, and node-platform esbuild would otherwise prefer CJS `main`.                                                            |
| `--banner:js` with `createRequire`   | Satisfies stray `require()` calls left in CJS-converted dependencies.                                                                                             |

The SDK's OTLP exporter chain is lazy-loaded, so injecting your own
`spanExporter` keeps Worker startup clean.

## Verify it works

Deploy, trigger one request, then confirm the trace appears in Agent Registry
for that `service_name`. A 200 from your handler does not prove the export
completed — a frozen instance returns successfully while dropping the batch.
Check the trace, not the response.

## Next steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/sdk/configuration">
    Export modes, flush tuning, and every option.
  </Card>

  <Card title="Send and verify traces" icon="check" href="/guides/traces/send-and-verify">
    Confirm ingestion end to end.
  </Card>
</CardGroup>
