IntermediateUpdated Jan 19, 2026
Building AI Features with Next.js 16 and Abstrakt
Learn how to integrate Abstrakt's AI capabilities into your Next.js 16 application with Server Components, Server Actions, and streaming.
ML
Marcus Lee
Developer Advocate
15 min read
Introduction
Next.js 16 brings powerful features for building AI applications: Server Components for secure API calls, Server Actions for form handling, and streaming for real-time updates.
Setup
npm install next@16 react@19 react-dom@19
Create .env.local:
ABSTRAKT_API_KEY=abs_your_api_key_here
API Client
typescript
// lib/abstrakt.ts
export async function generateImage(prompt: string) {
const response = await fetch('https://api.abstrakt.one/v1/models/flux-schnell/run', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ABSTRAKT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ input: { prompt } }),
});
return response.json();
}Server Components
tsx
// app/generate/page.tsx
export default async function GeneratePage({ searchParams }) {
if (!searchParams.prompt) return <PromptForm />;
const result = await generateImage(searchParams.prompt);
return <img src={result.result.images[0].url} alt={searchParams.prompt} />;
}Server Actions
tsx
// app/actions.ts
'use server'
export async function generateAction(formData: FormData) {
const prompt = formData.get('prompt') as string;
const result = await generateImage(prompt);
return { imageUrl: result.result.images[0].url };
}
// Form component
'use client'
export function GenerateForm() {
const [state, action, pending] = useActionState(generateAction, null);
return (
<form action={action}>
<input name="prompt" disabled={pending} />
<button disabled={pending}>{pending ? 'Generating...' : 'Generate'}</button>
{state?.imageUrl && <img src={state.imageUrl} />}
</form>
);
}Streaming with Suspense
tsx
import { Suspense } from 'react';
export default function Page({ searchParams }) {
return (
<Suspense fallback={<div className="animate-pulse" />}>
<GeneratedImage prompt={searchParams.prompt} />
</Suspense>
);
}Webhook Handler
typescript
// app/api/webhooks/abstrakt/route.ts
export async function POST(request: NextRequest) {
const body = await request.text();
const signature = request.headers.get('x-abstrakt-signature');
// Verify signature and process webhook
const payload = JSON.parse(body);
if (payload.event === 'job.completed') {
await handleJobCompleted(payload);
}
return NextResponse.json({ received: true });
}#nextjs#react#server-components#streaming