DEV Community

Nainik Mehta
Nainik Mehta

Posted on

Stop Streaming LLMs via Route Handlers: The Server Actions Shift

The Evolution of AI Integration in Next.js

For the past few years, building AI-powered features in Next.js followed a predictable, albeit tedious, pattern. You would spin up a /api/chat route, handle the incoming request, manually construct a ReadableStream, and then orchestrate a complex dance of fetch calls and chunk parsing on the client side.

While this approach worked, it was never truly "native" to the React ecosystem. It felt like plumbing—constantly fighting the framework to bridge the gap between server-side generation and client-side rendering. Today, that paradigm is shifting. With the maturation of Next.js Server Actions and the Vercel AI SDK, we can finally treat AI streaming as a first-class citizen in our applications.

Why Manual Route Handlers Are Holding You Back

If you are still building manual API routes for your LLM interactions, you are likely dealing with three major pain points that stifle developer velocity:

1. File Bloat and Architectural Overhead

Every time you add a new AI-powered feature, you are forced to create a new file in your app/api directory. This creates a fragmented codebase where the logic for your feature is split between the UI component and a distant API file. Over time, this makes maintaining your project significantly harder as your folder structure becomes cluttered with proxy endpoints.

2. The Loss of Type Safety

When you use fetch to hit an API route, you lose the inherent type safety that TypeScript provides. You are forced to manually define request types, cast JSON responses, and hope that the contract between your client and server stays intact. One small change in your API response structure can lead to runtime errors that TypeScript should have caught at compile time.

3. Client-Side Complexity

Reading a ReadableStream is not trivial. You have to handle chunking, manage state updates for every single token, and ensure that aborted requests don't cause memory leaks or UI glitches. This boilerplate code is not unique to your business logic; it’s infrastructure code that you shouldn't have to write.

The Paradigm Shift: Server Actions + Vercel AI SDK

The introduction of Server Actions in Next.js, combined with the powerful abstractions provided by the Vercel AI SDK, allows us to bypass the API layer entirely. Instead of fetching an endpoint, you invoke a function.

By using streamText and createStreamableValue, you can push data directly from the server to your client components.

Implementation Example

Here is how simple it becomes to stream LLM responses using Server Actions:

// app/actions.ts
'use server'

import { streamText } from 'ai';
import { createStreamableValue } from 'ai/rsc';
import { openai } from '@ai-sdk/openai';

export async function generateChatResponse(input: string) {
  const stream = createStreamableValue('');

  (async () => {
    const { textStream } = await streamText({
      model: openai('gpt-4o'),
      prompt: input,
    });

    for await (const delta of textStream) {
      stream.update(delta);
    }

    stream.done();
  })();

  return { output: stream.value };
}
Enter fullscreen mode Exit fullscreen mode

On the client side, the consumption is equally elegant:

// app/chat-component.tsx
'use client'

import { useState } from 'react';
import { readStreamableValue } from 'ai/rsc';
import { generateChatResponse } from './actions';

export default function ChatComponent() {
  const [response, setResponse] = useState('');

  const handleSend = async (input: string) => {
    const { output } = await generateChatResponse(input);

    for await (const delta of readStreamableValue(output)) {
      setResponse(current => current + delta);
    }
  };

  return (
    <div>
      <button onClick={() => handleSend('Hello!')}>Send</button>
      <p>{response}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The Benefits of the New Approach

By moving to this pattern, you gain several immediate advantages:

  • Zero Endpoints: Your project structure remains clean and feature-focused.
  • End-to-End Type Safety: Since your UI calls the Server Action directly, TypeScript ensures that the arguments and return values are strictly typed.
  • Zero Boilerplate: The Vercel AI SDK abstracts away the complexities of stream parsing, allowing you to focus on the user experience rather than web infrastructure.

Conclusion

The goal of modern web development is to reduce the friction between the developer's intent and the final product. Manual API routes for AI streaming were a necessary evil in the early days of LLM integration, but they are no longer the best practice.

By adopting Server Actions and the Vercel AI SDK, you can build AI features that feel like native React code. If you haven't made the switch yet, now is the time to refactor. Your codebase, and your future self, will thank you.

Top comments (1)

Collapse
 
101beardo profile image
Tarun Sharma

The type safety and zero boilerplate wins are real, but I would not drop route handlers entirely. Server Actions are POST only and Next serializes them, so if a user fires two AI calls at once the second waits on the first, which you feel right away in a chat UI. A route handler also gives you an actual endpoint a mobile client or a webhook or plain curl can hit, plus edge rate limiting before the model call. I would use actions for the simple in-app case and keep a handler around the moment anything outside the React tree needs the same stream.