Back to Baml

React/Next.js Setup

fern/01-guide/08-frameworks/01-react-nextjs/01-quick-start.mdx

0.222.08.0 KB
Original Source

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

<Note> **Requirements:** This integration requires **Next.js 15 or higher**. </Note>

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.

<CodeBlocks> ```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
'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>
  );
}
</CodeBlocks>

Quick Start

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

<Steps> ### Create a New Next.js Project

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

<CodeBlocks> ```bash npm npx create-next-app@latest my-baml-app ```
bash
pnpm create next-app my-baml-app
bash
yarn create next-app my-baml-app
bash
bun create next-app my-baml-app
bash
deno create next-app my-baml-app
</CodeBlocks>

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:

<CodeBlocks> ```bash npm npm install @boundaryml/baml @boundaryml/baml-nextjs-plugin ```
bash
pnpm add @boundaryml/baml @boundaryml/baml-nextjs-plugin
bash
yarn add @boundaryml/baml @boundaryml/baml-nextjs-plugin
bash
bun add @boundaryml/baml @boundaryml/baml-nextjs-plugin
bash
deno add @boundaryml/baml @boundaryml/baml-nextjs-plugin
</CodeBlocks>

Configure Next.js

Update your next.config.mjs:

<CodeBlocks> ```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
const { withBaml } = require('@boundaryml/baml-nextjs-plugin');

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

module.exports = withBaml()(nextConfig)
</CodeBlocks>

Initialize BAML

Create a new BAML project in your Next.js application: <Markdown src="../../../snippets/baml/cli/install/nodejs.mdx" />

This will create a baml_src directory with starter code.

Setup Environment Variables

Setup provider specific API Keys.

.env
OPENAI_API_KEY=sk-...
<Accordion title='(Optional) BAML Observability'> To enable observability with BAML, you'll first need to sign up for a [Boundary Studio](https://studio.boundaryml.com) account.
.env
BOUNDARY_API_KEY=your_api_key_here

OPENAI_API_KEY=sk-...
</Accordion>

Setup BAML Next.js Generator

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

diff
generator typescript {
-  output_type "typescript"
+  output_type "typescript/react"
  output_dir "../"
  version "0.76.2"
}

Generate BAML Client

<Markdown src="../../../snippets/baml/cli/generate.mdx" /> <Note> 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
  }
  ```
</Note>

Generated React Hooks

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

<CodeBlocks> ```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
'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>
  );
}
</CodeBlocks>

Update Package Scripts

Update your package.json scripts:

json
{
  "scripts": {
    "prebuild": "npm run generate",
    "generate": "baml-cli generate",
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
  }
}
</Steps>

Reference Documentation

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

Core Concepts

Hook Configuration

Next Steps