The way to instrument your application to automatically collect traces depends on the runtime and framework you are using.
Node.js
Braintrust auto-instrumentation for Node.js uses a startup hook. The hook patches supported AI libraries as your process starts, logging your LLM calls.
Version Requirement: Node.js 18.19.0+ or 20.6.0+ and above.
If you are using a bundler to build your application, also follow the guide for your specific bundler below. (Vite, Esbuild, Rollup, or Webpack)
1
Initialize the logger
Call initLogger() once, as soon as possible on application startup, before making any AI calls. The SDK reads BRAINTRUST_API_KEY from the environment configured above.
import { initLogger } from "braintrust";initLogger({ projectName: "My Project",});
2
Run with the import hook
Start your Node.js application with the Braintrust hook:
node --import braintrust/hook.mjs app.js
After following these steps, calls to your AI provider should be traced.
For a list of all supported AI providers see TypeScript SDK integrations.
Cloudflare
To trace LLM calls from your Cloudflare app, wrap your AI provider’s SDK with Braintrust. The example below uses OpenAI (for other providers, see TypeScript SDK integrations).
If you are using a bundler to build your application, also follow the guide for your specific bundler below. (Vite, Esbuild, Rollup, or Webpack)
Cloudflare Workers
Cloudflare Pages
1
Set Cloudflare secrets
Store your Braintrust API key as Cloudflare secret:
wrangler secret put BRAINTRUST_API_KEY
2
Setting the Node.js compatibility flag
Since the Braintrust SDK uses the Node.js AsyncLocalStorage API, you need to enable Node.js compatibility in your Wrangler configuration:
{ "compatibility_flags": ["nodejs_compat"]}
3
Initialize the logger and wrap your client
Inside fetch, initialize the logger with secrets from the env binding, wrap your OpenAI client, and pass logger.flush() to ctx.waitUntil() so buffered logs ship after the response returns.
import { initLogger, wrapOpenAI } from "braintrust";import OpenAI from "openai";interface Env { BRAINTRUST_API_KEY: string; OPENAI_API_KEY: string;}export default { async fetch( request: Request, env: Env, ctx: ExecutionContext, ): Promise<Response> { // Set up the braintrust logger const logger = initLogger({ projectName: "My Project", apiKey: env.BRAINTRUST_API_KEY, }); // Wrap the AI provider client const openAIClient = wrapOpenAI( new OpenAI({ apiKey: env.OPENAI_API_KEY, }), ); try { const result = await openAIClient.responses.create({ model: "gpt-5-mini", input: "What is the capital of France?", }); } finally { // Flush all tracing data to Braintrust in the background ctx.waitUntil(logger.flush()); } return Response.json(result); },};
1
Set Cloudflare secrets
Store your Braintrust API key as Cloudflare secret:
wrangler pages secret put BRAINTRUST_API_KEY
2
Setting the Node.js compatibility flag
Since the Braintrust SDK uses the Node.js AsyncLocalStorage API, you need to enable Node.js compatibility in your Wrangler configuration:
{ "compatibility_flags": ["nodejs_compat"]}
3
Initialize the logger and wrap your client
Inside onRequest, initialize the logger with secrets from the context.env binding, wrap your OpenAI client, and pass logger.flush() to context.waitUntil() so buffered logs ship after the response returns.
import { initLogger, wrapOpenAI } from "braintrust";import OpenAI from "openai";interface Env { BRAINTRUST_API_KEY: string; OPENAI_API_KEY: string;}export const onRequest: PagesFunction<Env> = async (context) => { // Set up the braintrust logger const logger = initLogger({ projectName: "My Project", apiKey: context.env.BRAINTRUST_API_KEY, }); // Wrap the AI provider client const openAIClient = wrapOpenAI( new OpenAI({ apiKey: context.env.OPENAI_API_KEY, }), ); try { const result = await openAIClient.responses.create({ model: "gpt-5-mini", input: "What is the capital of France?", }); } finally { // Flush all tracing data to Braintrust in the background context.waitUntil(logger.flush()); } return Response.json(result);};
Deno
To trace LLM calls from your Deno app, wrap your AI provider’s SDK with Braintrust. The example below uses OpenAI (for other providers, see TypeScript SDK integrations).
If you are using a bundler to build your application, also follow the guide for your specific bundler below. (Vite, Esbuild, Rollup, or Webpack)
1
Initialize the logger and wrap your client
Read your BRAINTRUST_API_KEY from Deno.env, initialize Braintrust, and wrap the provider client before making AI calls.
import { initLogger, wrapOpenAI } from "npm:braintrust";import OpenAI from "npm:openai";const braintrustApiKey = Deno.env.get("BRAINTRUST_API_KEY");const logger = initLogger({ projectName: "My Project", apiKey: braintrustApiKey,});const openAIClient = wrapOpenAI(new OpenAI());try { const result = await openAIClient.responses.create({ model: "gpt-5-mini", input: "What is the capital of France?", });} finally { await logger.flush();}console.log(result.output_text);
2
Run with Deno permissions
Grant environment variable access via --allow-env and network access for Braintrust via --allow-net and run your application.
deno run \ --allow-env=BRAINTRUST_API_KEY \ --allow-net=www.braintrust.dev,api.braintrust.dev,api-eu.braintrust.dev \ main.ts
AWS Lambda
To trace LLM calls from a Node.js Lambda function, initialize Braintrust outside the handler once, wrap your AI provider’s SDK, and flush before the invocation returns. AWS Lambda does not keep background promises alive after the handler completes, so set asyncFlush: false when initializing the logger.
If you are using a bundler to build your application, also follow the guide for your specific bundler below. (Vite, Esbuild, Rollup, or Webpack)
1
Initialize the logger and wrap your client
Create the logger and provider client at module scope so Lambda can reuse them across warm invocations.
lambda.ts
import { initLogger, wrapOpenAI } from "braintrust";import OpenAI from "openai";const logger = initLogger({ projectName: "My Project", apiKey: process.env.BRAINTRUST_API_KEY, asyncFlush: false,});const openAIClient = wrapOpenAI(new OpenAI());export async function handler() { try { const result = await openAIClient.responses.create({ model: "gpt-5-mini", input: "What is the capital of France?", }); return { statusCode: 200, headers: { "content-type": "application/json" }, body: JSON.stringify({ answer: result.output_text, }), }; } finally { await logger.flush(); }}
Next.js
To trace LLM calls from a Next.js app, wrap your Next.js config and initialize Braintrust in Next’s instrumentation.ts.
1
Configure the Next.js Config
Wrap your Next.js Config with wrapNextjsConfigWithBraintrust.
next.config.ts
import { createRequire } from "module";import { type NextConfig } from "next";import { wrapNextjsConfigWithBraintrust } from "braintrust/next";const nextConfig: NextConfig = {};export default wrapNextjsConfigWithBraintrust(nextConfig);
2
Initialize the logger
Create instrumentation.ts in the project root, or src/instrumentation.ts if your app uses src/ and initialize the logger.
instrumentation.ts
import { initLogger } from "braintrust";export function register() { if (process.env.NEXT_RUNTIME === "nodejs" || process.env.NEXT_RUNTIME === "edge") { initLogger({ projectName: "My Project", }); }}
Nest.js
To trace LLM calls from a Nest.js application, initialize Braintrust before Nest creates your application module, then start the Node.js process with the Braintrust hook.
1
Initialize the logger
Call initLogger() before NestFactory.create() and adding an import for braintrust/apply-auto-instrumentation. This ensures Braintrust is ready before Nest constructs providers that may create AI clients.
src/main.ts
// Add the `braintrust/apply-auto-instrumentation` import before any other imports.// Import order is important because the Braintrust import can only instrument subsequent imports.import "braintrust/apply-auto-instrumentation":import { NestFactory } from "@nestjs/core";import { initLogger } from "braintrust";import { AppModule } from "./app.module";initLogger({ projectName: "My Project",});async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(process.env.PORT ?? 3000);}void bootstrap();
2
Start Nest with the import hook
Update the scripts you use to run Nest so every normal launch path loads braintrust/hook.mjs. For development with nest start, use NODE_OPTIONS so the hook is inherited by the Nest CLI’s Node process. For production, pass --import to the compiled app directly.
To trace LLM calls from a Nitro server, initialize Braintrust when Nitro starts, add the Braintrust Rollup plugin to the Nitro server build, and flush traces from global middleware.
1
Instrument the server bundle
Add the Braintrust Rollup plugin to nitro.config.ts. Nitro builds the server bundle with Rollup, so this instruments supported AI SDK packages during the Nitro build.
nitro.config.ts
import { braintrustRollupPlugin } from "braintrust/rollup";import { defineConfig } from "nitro";export default defineConfig({ rollupConfig: { plugins: [braintrustRollupPlugin()], },});
2
Initialize the logger
Add a Nitro plugin that initializes Braintrust once when Nitro starts.
plugins/braintrust.ts
import { initLogger } from "braintrust";import { definePlugin } from "nitro";export default definePlugin(() => { initLogger({ projectName: "My Project", });});
3
Add a flush middleware
Add a global middleware that runs after each handler calling flush() in a finally block and pass the promise to event.waitUntil().
This will make Nitro keep the runtime alive long enough to send buffered traces after the response is ready on runtimes that are supported (like Vercel and Cloudflare).
Add a server plugin that initializes Braintrust when Nitro starts and schedules a flush after each response.
server/plugins/braintrust.ts
import { initLogger } from "braintrust";export default defineNitroPlugin((nitroApp) => { initLogger({ projectName: "My Project", });});
3
Add a flush middleware
Add a global middleware that runs on each request calling flush() and pass the promise to event.waitUntil().
This will make Nuxt keep the runtime alive long enough to send buffered traces after the response is ready on runtimes that are supported (like Vercel and Cloudflare).
Update the scripts you use to run Nuxt so every normal launch path loads braintrust/hook.mjs. For development with nuxt dev, use NODE_OPTIONS so the hook is inherited by the Nuxt CLI’s Node process. For production, pass --import to the compiled app directly.
To trace LLM calls in React Router Framework applications, add the Braintrust Vite plugin to the config, initialize the logger in the server entry, and add a node import hook to your server start.
1
Instrument the Vite build
Add the Braintrust Vite plugin to vite.config.ts alongside the React Router plugin.
vite.config.ts
import { reactRouter } from "@react-router/dev/vite";import { defineConfig } from "vite";import { braintrustVitePlugin } from "braintrust/vite";export default defineConfig(() => ({ plugins: [ braintrustVitePlugin(), reactRouter(), ],}));
2
Initialize the logger
If your app uses the default hidden server entry, reveal it first:
npx react-router reveal entry.server
Then call initLogger() in the module scope before importing or constructing any AI clients.
app/entry.server.tsx
import { initLogger } from "braintrust";initLogger({ projectName: "My Project",});
To trace LLM calls on SvelteKit applications, add the Braintrust Vite plugin and initialize the braintrust logger.
1
Instrument the Vite build
Add the Braintrust Vite plugin before sveltekit() in vite.config.ts.
vite.config.ts
import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { braintrustVitePlugin } from "braintrust/vite";export default defineConfig(() => ({ plugins: [ braintrustVitePlugin(), sveltekit(), ],}));
2
Initialize and flush from server hooks
Code in SvelteKit hook modules runs when the app starts. Initialize Braintrust at module scope and flush from handle.
src/hooks.server.ts
import { flush, initLogger } from "braintrust";import { type Handle } from "@sveltejs/kit";initLogger({ projectName: "My Project",});export const handle: Handle = async ({ event, resolve }) => { try { return await resolve(event); } finally { void flush(); }};
TanStack Start
To trace LLM calls from TanStack Start, initialize Braintrust in src/start.ts, add global request middleware to flush traces, and instrument the Vite build.
1
Instrument the Vite build
Add the Braintrust Vite plugin:
vite.config.ts
import { tanstackStart } from "@tanstack/react-start/plugin/vite";import viteReact from "@vitejs/plugin-react";import { nitro } from "nitro/vite";import { defineConfig } from "vite";import { braintrustVitePlugin } from "braintrust/vite";export default defineConfig(() => ({ plugins: [ braintrustVitePlugin(), tanstackStart(), nitro(), viteReact(), ],}));
2
Initialize and flush from global middleware
Initialize Braintrust in module scope of a global middleware and flush in a finally block.
Add the Braintrust Vite plugin to your Vite config. The plugin instruments supported AI packages at build time.
vite.config.ts
import { defineConfig } from "vite";import { braintrustVitePlugin } from "braintrust/vite";export default defineConfig({ plugins: [braintrustVitePlugin()],});
esbuild
Add the Braintrust esbuild plugin to the plugins array in your build script. The plugin runs during bundling and instruments supported AI SDK packages before the bundle is written.
build.ts
import * as esbuild from "esbuild";import { braintrustEsbuildPlugin } from "braintrust/esbuild";await esbuild.build({ entryPoints: ["src/index.ts"], bundle: true, format: "esm", outfile: "dist/index.js", plugins: [braintrustEsbuildPlugin()],});
Webpack
Add the Braintrust Webpack plugin to your Webpack config. The plugin instruments supported AI SDK packages at build time.
webpack.config.ts
import { braintrustWebpackPlugin } from "braintrust/webpack";export default { plugins: [braintrustWebpackPlugin()],};
Rollup
Add the Braintrust Rollup plugin to your Rollup config. The plugin instruments supported AI SDK packages during the Rollup build.