> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.boundaryml.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.boundaryml.com/_mcp/server.

# React/Next.js Setup

This guide walks you through setting up BAML with React/Next.js, leveraging Server Actions and React Server Components for optimal performance.

**Requirements:** This integration requires **Next.js 15 or higher**.

## Example Usage

BAML automatically generates a server action and React hook for your BAML functions, with built-in support for both streaming and non-streaming modes. For details on the generated hooks, see [Generated Hooks](/ref/baml_client/react-next-js/use-function-name-hook).

```baml title="baml_src/prompt.baml"
class Story {
  title string @stream.not_null
  content string @stream.not_null
}

function WriteMeAStory(input: string) -> Story {
  client "openai/gpt-5"
  prompt #"
    Tell me a story

    {{ ctx.output_format() }}

    {{ _.role("user") }}

    Topic: {{input}}
  "#
}
```

```bash title="Generate BAML client"
npx baml-cli generate

pnpm exec baml-cli generate

yarn baml-cli generate

bun baml-cli generate

deno run --unstable-sloppy-imports -A npm:@boundaryml/baml/baml-cli generate
```

```tsx title="app/components/story-form.tsx" {8,10,15-16}
'use client'

  // ✅ Automatically generates a server action and React hook

import { useWriteMeAStory } from "@/baml_client/react/hooks";

export function StoryForm() {
  const writeMeAStory = useWriteMeAStory();

  return (
    <div>
      <button
        onClick={() => writeMeAStory.mutate("About a cat in a hat")}
        disabled={writeMeAStory.isLoading}>
        {writeMeAStory.isLoading ? 'Generating...' : 'Generate Story'}
      </button>

      <div>
        <h4>{writeMeAStory.data?.title}</h4>
        <p>{writeMeAStory.data?.content}</p>
      </div>

      {writeMeAStory.error && <div>Error: {writeMeAStory.error.message}</div>}
    </div>
  );
}
```

## Quick Start

Follow the step-by-step instructions below to set up BAML in a new or existing Next.js project.

### Create a New Next.js Project

First, create a new Next.js project with the App Router:

```bash npm
npx create-next-app@latest my-baml-app
```

```bash pnpm
pnpm create next-app my-baml-app
```

```bash yarn
yarn create next-app my-baml-app
```

```bash bun
bun create next-app my-baml-app
```

```bash deno
deno create next-app my-baml-app
```

When prompted, make sure to:

* Select **Yes** for "Would you like to use TypeScript?"
* Select **Yes** for "Would you like to use the App Router? (recommended)"
* Configure other options as needed for your project

### Install Dependencies

Next, install BAML and its dependencies:

```bash npm
npm install @boundaryml/baml @boundaryml/baml-nextjs-plugin
```

```bash pnpm
pnpm add @boundaryml/baml @boundaryml/baml-nextjs-plugin
```

```bash yarn
yarn add @boundaryml/baml @boundaryml/baml-nextjs-plugin
```

```bash bun
bun add @boundaryml/baml @boundaryml/baml-nextjs-plugin
```

```bash deno
deno add @boundaryml/baml @boundaryml/baml-nextjs-plugin
```

### Configure Next.js

Update your `next.config.mjs`:

```typescript title="next.config.ts" {1,8}
import { withBaml } from '@boundaryml/baml-nextjs-plugin';
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // ... existing config
};

export default withBaml()(nextConfig);
```

```javascript title="next.config.mjs" {1,8}
import { withBaml } from '@boundaryml/baml-nextjs-plugin';
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // ... existing config
};

export default withBaml()(nextConfig);
```

```javascript title="next.config.js" {1,8}
const { withBaml } = require('@boundaryml/baml-nextjs-plugin');

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ... existing config
}

module.exports = withBaml()(nextConfig)
```

### Initialize BAML

Create a new BAML project in your Next.js application:

```bash npm
npx baml-cli init
```

```bash pnpm
pnpm exec baml-cli init
```

```bash yarn
yarn baml-cli init
```

```bash bun
bun baml-cli init
```

```bash deno
deno run --unstable-sloppy-imports -A npm:@boundaryml/baml/baml-cli init
```

This will create a `baml_src` directory with starter code.

### Setup Environment Variables

Setup provider specific API Keys.

```.env .env.local
OPENAI_API_KEY=sk-...
```

To enable observability with BAML, you'll first need to sign up for a [Boundary Studio](https://studio.boundaryml.com) account.

```.env .env.local
BOUNDARY_API_KEY=your_api_key_here

OPENAI_API_KEY=sk-...
```

### Setup BAML Next.js Generator

Update the `baml_src/generators.baml` file to use the React/Next.js generator.

```diff title="baml_src/generators.baml"
generator typescript {
-  output_type "typescript"
+  output_type "typescript/react"
  output_dir "../"
  version "0.76.2"
}
```

### Generate BAML Client

```bash npm
npx baml-cli generate
```

```bash pnpm
pnpm exec baml-cli generate
```

```bash yarn
yarn baml-cli generate
```

```bash bun
bun baml-cli generate
```

```bash deno
deno run --unstable-sloppy-imports -A npm:@boundaryml/baml/baml-cli generate
```

If you need baml\_client to be 'ESM' compatible, you can add the following `generator` configuration to your `.baml` file:

```baml
generator typescript {
  ...
  module_format "esm" // the default is "cjs" for CommonJS
}
```

### Generated React Hooks

BAML automatically generates type-safe Next.js server actions and React hooks for your BAML functions.

```baml title="baml_src/prompt.baml"
class Story {
  title string @stream.not_null
  content string @stream.not_null
}

function WriteMeAStory(input: string) -> Story {
  client "openai/gpt-5"
  prompt #"
    Tell me a story

    {{ ctx.output_format() }}

    {{ _.role("user") }}

    Topic: {{input}}
  "#
}
```

```tsx title="Non-Streaming Example"
'use client'

import { useWriteMeAStory } from "@/baml_client/react/hooks";
import type { Story } from "@/baml_client/types";

export function StoryForm() {
  const writeMeAStory = useWriteMeAStory({ stream: false });

  return (
    <div>
      <button onClick={() => writeMeAStory.mutate("About a cat in a hat")}>
        {writeMeAStory.isLoading ? 'Generating...' : 'Generate Story'}
      </button>

      {writeMeAStory.data && (
        <div>
          <h4>{writeMeAStory.data.title}</h4>
          <p>{writeMeAStory.data.content}</p>
        </div>
      )}

      {writeMeAStory.error && <div>Error: {writeMeAStory.error.message}</div>}
    </div>
  );
}
```

```tsx title="Streaming Example"
'use client'

import { useWriteMeAStory } from "@/baml_client/react/hooks";
import type { Story } from "@/baml_client/types";

export function StreamingStoryForm() {
  const writeMeAStory = useWriteMeAStory({
    onStreamData: (partial) => {
      // Handle real-time updates
      console.log('Story in progress:', partial);
    },
    onFinalData: (final) => {
      // Handle completed story
      console.log('Story completed:', final);
    }
  });

  return (
    <div>
      <button
        onClick={() => writeMeAStory.mutate("About a cat in a hat")}
        disabled={writeMeAStory.isLoading}>
        {writeMeAStory.isLoading ? 'Generating...' : 'Generate Story'}
      </button>

      {writeMeAStory.data && (
        <div>
          <h4>{writeMeAStory.data.title}</h4>
          <p>{writeMeAStory.data.content}</p>
        </div>
      )}

      {writeMeAStory.error && <div>Error: {writeMeAStory.error.message}</div>}
    </div>
  );
}
```

### Update Package Scripts

Update your `package.json` scripts:

```json {3,4}
{
  "scripts": {
    "prebuild": "npm run generate",
    "generate": "baml-cli generate",
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
  }
}
```

## Reference Documentation

For complete API documentation of the React/Next.js integration, see:

### Core Concepts

* [Generated Hooks](/ref/baml_client/react-next-js/use-function-name-hook) - Auto-generated hooks for each BAML function

### Hook Configuration

* [HookInput](/ref/baml_client/react-next-js/hook-input) - Configuration options for hooks
* [HookOutput](/ref/baml_client/react-next-js/hook-output) - Return value types and states
* [Error Types](/ref/baml_client/errors/overview) - Error handling and types

## Next Steps

* Check out the [BAML Examples](https://github.com/BoundaryML/baml-examples/tree/main/nextjs-starter) for more use cases