Next.js
Wire Crux into a Next.js 16 App Router project, covering Server Actions, streaming Route Handlers, and the recommended file layout.
This guide gets Crux running in a Next.js 16 App Router project. Crux prompts run on the server: define them in a shared module and call them from Server Actions or Route Handlers.
Crux is in alpha. Public packages are available on npm; use the install commands below to get started.
Install
bash npm install @use-crux/core @use-crux/ai @ai-sdk/openai zod
bash pnpm add @use-crux/core @use-crux/ai @ai-sdk/openai zod
bash yarn add @use-crux/core @use-crux/ai @ai-sdk/openai zod
bash bun add @use-crux/core @use-crux/ai @ai-sdk/openai zod
OPENAI_API_KEY=sk-...The @ai-sdk/openai provider reads OPENAI_API_KEY automatically.
Recommended layout
app/
actions/
summarize.ts ← Server Action that calls generate()
api/
chat/route.ts ← Route Handler with streaming
lib/
ai/
prompts.ts ← Prompt definitions
contexts.ts ← Shared contexts
config.ts ← policy/defaults config (optional)This is a recommendation, not a requirement. Crux has no required project structure: organize however fits your codebase.
Step 1: Define a prompt
Create the prompt module
import { prompt, context } from "@use-crux/core";
import { z } from "zod";
const brand = context({
id: "brand",
priority: 30,
system: "Use a professional tone. Be concise.",
});
export const summarize = prompt({
id: "summarize",
use: [brand],
input: z.object({ text: z.string() }),
output: z.object({
summary: z.string(),
keyPoints: z.array(z.string()),
}),
system: "Summarize the given text.",
prompt: ({ input }) => input.text,
});Call it from a Server Action
"use server";
import { generate } from "@use-crux/ai";
import { openai } from "@ai-sdk/openai";
import { summarize } from "@/lib/ai/prompts";
export async function summarizeText(text: string) {
const result = await generate(summarize, {
model: openai("gpt-4o-mini"),
input: { text },
});
return result.object;
}Use it in a Server Component or Client Component
import { summarizeText } from "./actions/summarize";
export default async function Page() {
const result = await summarizeText("Long article text here...");
return (
<article>
<p>{result.summary}</p>
<ul>
{result.keyPoints.map((point) => (
<li key={point}>{point}</li>
))}
</ul>
</article>
);
}Streaming from a Route Handler
For chat or any long-form output, stream from a Route Handler:
import { createUIMessageStreamResponse, stream } from "@use-crux/ai";
import { openai } from "@ai-sdk/openai";
import { chatPrompt } from "@/lib/ai/prompts";
export async function POST(req: Request) {
const { message } = await req.json();
const result = await stream(chatPrompt, {
model: openai("gpt-4o"),
input: { message },
});
return createUIMessageStreamResponse(result);
}The Vercel AI SDK adapter's stream() returns a canonical Crux stream result.
Pass it to createUIMessageStreamResponse(result) for seamless integration
with useChat on the client.