fern/01-guide/08-frameworks/01-react-nextjs/01-quick-start.mdx
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>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
'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>
);
}
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 ProjectFirst, create a new Next.js project with the App Router:
<CodeBlocks> ```bash npm npx create-next-app@latest my-baml-app ```pnpm create next-app my-baml-app
yarn create next-app my-baml-app
bun create next-app my-baml-app
deno create next-app my-baml-app
When prompted, make sure to:
Next, install BAML and its dependencies:
<CodeBlocks> ```bash npm npm install @boundaryml/baml @boundaryml/baml-nextjs-plugin ```pnpm add @boundaryml/baml @boundaryml/baml-nextjs-plugin
yarn add @boundaryml/baml @boundaryml/baml-nextjs-plugin
bun add @boundaryml/baml @boundaryml/baml-nextjs-plugin
deno add @boundaryml/baml @boundaryml/baml-nextjs-plugin
Update your next.config.mjs:
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);
const { withBaml } = require('@boundaryml/baml-nextjs-plugin');
/** @type {import('next').NextConfig} */
const nextConfig = {
// ... existing config
}
module.exports = withBaml()(nextConfig)
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 provider specific API Keys.
OPENAI_API_KEY=sk-...
BOUNDARY_API_KEY=your_api_key_here
OPENAI_API_KEY=sk-...
Update the baml_src/generators.baml file to use the React/Next.js generator.
generator typescript {
- output_type "typescript"
+ output_type "typescript/react"
output_dir "../"
version "0.76.2"
}
```baml
generator typescript {
...
module_format "esm" // the default is "cjs" for CommonJS
}
```
</Note>
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>
);
}
'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 your package.json scripts:
{
"scripts": {
"prebuild": "npm run generate",
"generate": "baml-cli generate",
"dev": "next dev",
"build": "next build",
"start": "next start",
}
}
For complete API documentation of the React/Next.js integration, see: