Using Next.js with Agentuity

Connect Agentuity service clients, local development, and deploy packaging to an App Router project

Call Agentuity services (key-value, AI Gateway, queues) from Next.js App Router route handlers. Use agentuity build to inspect the package, then deploy with agentuity deploy.

Create a Starter

The quickest way to start is with the Agentuity CLI:

npm create agentuity -- --name my-next-app --framework nextjs --services keyvalue
cd my-next-app

The starter includes a working translation demo: a React page that calls an API route using AIGatewayClient. Adding --services keyvalue installs @agentuity/keyvalue and updates the starter checklist, but it does not add another route by itself. The key files:

FilePurpose
src/app/page.tsxClient UI that calls the API route
src/app/api/translate/route.tsRoute handler that calls the AI Gateway
package.jsondev, build, and deploy scripts pre-wired

Add to an Existing App

Install the CLI as a dev dependency, then import the project:

npm install -D @agentuity/cli
npx agentuity project import --validate-only   # dry run: checks config only
npx agentuity project import                   # registers the project and writes agentuity.json

npm install -D installs the CLI as a project-local dev dependency, not a global install. Use npx to run that local CLI. For Bun, pnpm, and Yarn equivalents, see Local versus global CLI.

agentuity project import writes the local project metadata that agentuity deploy expects. Run it once before the first deploy.

What Agentuity adds

AreaNext.js keepsAgentuity adds
routingApp Router pages and app/api/**/route.ts handlersservice clients you import in server code
local devnext devagentuity dev supplies service credentials
buildnext build and standalone outputagentuity build runs the build and packages launch metadata
deploythe generated standalone serveragentuity deploy ships the packaged app

Service Client Example

Route handlers use standalone service clients. They do not need an Agentuity-owned router or createApp().

npm install @agentuity/keyvalue
typescriptsrc/app/api/notes/route.ts
import { KeyValueClient } from '@agentuity/keyvalue';
import { NextResponse } from 'next/server';
 
interface Note {
	readonly id: string;
	readonly text: string;
	readonly createdAt: string;
}
 
// Instantiated once at module load; reads AGENTUITY_SDK_KEY from the environment
const kv = new KeyValueClient(); 
 
export async function POST(request: Request): Promise<NextResponse> {
	const body: unknown = await request.json();
 
	if (typeof body !== 'object' || body === null || !('text' in body)) {
		return NextResponse.json({ error: 'text is required' }, { status: 400 });
	}
 
	const { text } = body;
	if (typeof text !== 'string' || !text.trim()) {
		return NextResponse.json({ error: 'text must be a non-empty string' }, { status: 400 });
	}
 
	const note: Note = {
		id: crypto.randomUUID(),
		text: text.trim(),
		createdAt: new Date().toISOString(),
	};
 
	await kv.set('notes', note.id, note, { ttl: 60 * 60 * 24 * 7 }); // 7-day TTL
 
	return NextResponse.json({ note });
}
 
export async function GET(request: Request): Promise<NextResponse> {
	const { searchParams } = new URL(request.url);
	const id = searchParams.get('id');
 
	if (!id) {
		return NextResponse.json({ error: 'id query param is required' }, { status: 400 });
	}
 
	const result = await kv.get<Note>('notes', id); 
 
	if (!result.exists) {
		return NextResponse.json({ error: 'not found' }, { status: 404 });
	}
 
	// result.data is typed as Note because of the generic
	return NextResponse.json({ note: result.data });
}

KeyValueClient reads AGENTUITY_SDK_KEY from the environment. Run the app with agentuity dev so the linked project key is available during local development.

AI Gateway Route Example

Use AIGatewayClient for generic model calls. The project SDK key authenticates the request, and the model ID is app configuration or request input.

npm install @agentuity/aigateway zod
typescriptsrc/app/api/chat/route.ts
import { AIGatewayClient } from '@agentuity/aigateway';
import { NextResponse } from 'next/server';
import { z } from 'zod';
 
const DEFAULT_MODEL = 'openai/gpt-5.4-mini';
const gateway = new AIGatewayClient(); 
 
const requestSchema = z.object({
	message: z.string(),
	model: z.string().optional(),
});
 
export async function POST(request: Request): Promise<NextResponse> {
	const body: unknown = await request.json();
	const parsed = requestSchema.safeParse(body); 
 
	if (!parsed.success) {
		return NextResponse.json({ error: 'message is required' }, { status: 400 });
	}
 
	const { message } = parsed.data;
	const model = parsed.data.model ?? DEFAULT_MODEL;
	const result = await gateway.completeText({ 
		model,
		messages: [{ role: 'user', content: message }],
	});
 
	if (!result.hasText) {
		return NextResponse.json({ error: 'model returned no text' }, { status: 502 });
	}
 
	return NextResponse.json({
		reply: result.text,
		model,
	});
}

Use the model id exactly as it appears in the AI Gateway model catalog. Use a provider SDK directly only when the route depends on provider-specific APIs such as OpenAI Responses state or Anthropic tool_use blocks.

Run Locally

Start the app with agentuity dev. When the linked project key is available, the CLI supplies AGENTUITY_SDK_KEY to the Next.js process:

agentuity dev

Smoke-test the route:

curl http://localhost:3000/api/chat \
  -H "content-type: application/json" \
  -d '{"message":"Hello"}'

Deployed Environment Variables

Configure the variables your deployed app needs. Direct AIGatewayClient calls use AGENTUITY_SDK_KEY; the model ID in this example is normal app configuration or request input.

VariableUsed by
AGENTUITY_SDK_KEYAgentuity service clients and @agentuity/aigateway
DATABASE_URLdatabase routes
AWS_*object storage routes; see Object Storage for exact variables

Validate Before Deploy

Run the framework build when you want Next.js-only feedback, then run the Agentuity build. agentuity build runs the framework build during packaging and produces .agentuity/launch.json with the start command for the deployed container.

npm run build
npx agentuity build
cat .agentuity/launch.json   # verify the command points at the standalone server

The agentuity build adapter sets NEXT_PRIVATE_STANDALONE=true at build time so Next.js produces .next/standalone/. Adding explicit output: 'standalone' to next.config.ts is safer: it works regardless of the adapter's env injection and makes the intent visible in your config file.

typescriptnext.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
	output: 'standalone', // produces .next/standalone/ with a minimal server.js
};
 
export default nextConfig;

With standalone output, a valid package contains the standalone server, .next/static/, and public/. The launch command must reference the generated server.js. In monorepos or nested workspaces, that file may be under the traced project path instead of the output root.

Deploy only after the framework build, Agentuity build, and a local packaged validation of / and at least one route handler pass:

agentuity deploy --confirm

Common Gotchas

SymptomCheck
Service client returns 401 or auth errorsRun with agentuity dev, or set AGENTUITY_SDK_KEY manually
Model call returns an auth errorVerify AGENTUITY_SDK_KEY is available to the route handler. See AI Gateway
launch.json starts node node_modules/.bin/next startDo not deploy that package. Rebuild after the adapter writes a command that starts the standalone server.js output
.next/standalone is empty after buildConfirm Next.js version is 12+; older versions do not support standalone output
Files outside the app root are missing in the standalone bundleSet outputFileTracingRoot in next.config.ts to include monorepo paths

Framework Docs

Next Steps