Eric Crooks - Software Engineer - Raleigh, North Carolina
Eric Crooks
Software engineer, Nasdaq trader, and US Army Veteran. Based in Apex, North Carolina.
Back to all journal entries

Calling Claude on Next.js With Drash

A new Drash example: a Next.js chat app that streams Claude's replies and remembers the conversation. The only framework-specific part is a route handler.

Drash has a new example app: a Next.js chat app that uses Claude.

The Next.js Claude example streaming a reply The example app streaming a reply from Claude Opus 5

It streams replies as they're written, remembers the conversation on the server, and keeps your API key where it belongs. A little over a month ago I posted about Drash and how it's built on the web's own primitives. This example is what that looks like inside a framework you probably already use (Next.js).

What It Is#

It's a chat UI with two tabs. Each tab sends the same conversation to a different endpoint:

EndpointAnswers with
POST /api/chatReceive all text once the model has finished
POST /api/chat/streamReceive text as the model writes it

A third endpoint at /api/conversation hands the history back (GET), so a reload picks up where you left off, and forgets it (DELETE) when you start over. There's also a model picker. The list of models lives in one file that both the browser and the server import, so the two sides can't disagree about which models are allowed.

Why Drash Fits in Next.js#

A Next.js route handler is a file that exports one function per HTTP method. Each function is handed a Web Request and returns a Response.

That's also Drash's entire contract. A Request goes in and a Response comes out. So mounting a Drash application in Next.js takes no adapter and no plugin. You just pass the request through:

View the full example at https://drash.crookse.com/examples/frameworks/next-js/calling-claude/
//
// Code is shortened for brevity.
// Copying the code will not work.
//
 
const app = Application
  .builder()
  .resources(ChatStream)
  .build();
 
export async function GET(request: Request) {
  return app.handle<Response>(request);
}
 
export async function POST(request: Request) {
  return app.handle<Response>(request);
}
 
export async function DELETE(request: Request) {
  return app.handle<Response>(request);
}

Streaming doesn't need anything from Drash either. The streaming resource returns a Response whose body happens to be a ReadableStream, and Drash hands it back untouched.

This is the transfer tax again. Nothing you learn from this example is Drash trivia. Server-sent events, ReadableStream, Response.json(), and cookies all work the same on Deno, Bun, Node, a Cloudflare Worker, or whatever you move to next.

Try Both Tabs#

With the non-streaming endpoint, you can wait a long time before anything appears. With the streaming endpoint, text starts showing up almost right away. The model is equally fast in both cases. The only difference is when you get to see its output.

The documentation also covers the client side: reading the stream, reassembling frames when a network failure occurs mid-frame, and displaying messages that fail to deliver (just like Apple Messages).

Where to Get It#

View the docs and code example at your leisure:

Or if you have a coding agent:

Create a new project at [~/SOME/FOLDER] from https://github.com/drashland/drash/tree/main/examples/frameworks/next-js-claude
open sourcedrashnext.jsclaudeaiweb standards

Looking to connect?