Node.js 22: Streaming Claude Tokens with Bedrock and SSE Setup
Node.js 22 simplifies streaming Claude tokens with Bedrock using server-sent events (SSE), enhancing real-time user experience.
- Topic
- Node.js
- Reading time
- 5 min
- Length
- 1,033 words
- Published
- Sep 18, 2026
09:05 pm IST
In this article
Node.js 22 is making waves by smoothing out the integration for streaming Claude tokens using Bedrock. With server-sent events (SSE) now in play, we can stream tokens straight to the browser as they come through, enhancing the user experience by making it more live and dynamic. Thanks to Node's native fetch API, setting up a Lambda-backed SSE endpoint requires much less hassle, and brings real-time interactions closer to applications using this technology.
Why Streaming Matters
Usually, when dealing with large language models (LLMs) like Claude, applications would hold off displaying any text until the whole response was ready. It’s not ideal, especially for chat-like apps where users want quick feedback. Streaming changes the game by delivering each token—as soon as it’s churned out by the model—directly to the client. This makes the conversation feel instant, seeing the response unfold right in front of you.
Streaming brings several benefits:
- It feels interactive, like chatting with a live agent.
- It reduces the time users spend waiting, as tokens process more promptly.
- It’s a memory saver on the server side since you don’t need to hoard entire responses.
The Streaming Setup
Getting streaming up and running with Bedrock hinges on setting the stream flag to true in your request payload. Miss this, and Bedrock will just send a full JSON object, and you lose out on streaming perks. The AWS SDK for JavaScript, using the @aws-sdk/client-bedrock-runtime package, takes care of the heavy lifting when dealing with the Bedrock Runtime API. It handles signing requests and retries, making life much easier when setting up your streaming client.
// src/bedrockClient.ts
import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime";
export const bedrockClient = new BedrockRuntimeClient({
region: "us-east-1",
requestHandler: undefined,
});
By keeping the Bedrock client active across Lambda invocations, you dodge the lag that comes with setting up HTTP connections again and again. It's especially vital in serverless setups like AWS Lambda, where cold starts could slow you down.
Using Native Fetch for Token Streaming
Node.js 22's built-in fetch API means you can ditch extra HTTP libraries. It trims down your deployment package and works perfectly with SSE since streams are represented as ReadableStream objects. Here’s how you can send a streaming request to Bedrock:
// src/handler.ts
import { bedrockClient } from "./bedrockClient";
import { InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";
async function callClaudeStream(prompt: string): Promise<ReadableStream<Uint8Array>> {
const command = new InvokeModelCommand({
modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0",
body: JSON.stringify({
prompt,
maxTokens: 512,
temperature: 0.7,
stream: true,
}),
accept: "application/json",
contentType: "application/json",
});
const response = await bedrockClient.send(command);
if (!response.body) {
throw new Error("Bedrock returned an empty body – something went wrong.");
}
return response.body as ReadableStream<Uint8Array>;
}
By using InvokeModelCommand with stream: true, you get a byte stream that you can pipe directly to the browser. This keeps the data flowing smoothly from the model to the interface, maintaining a seamless user experience.
Building an SSE Endpoint in Lambda
Server-Sent Events (SSE) make it straightforward to stream data from server to browser via HTTP. For token streams, SSE is a great fit, operating over HTTPS without the need for extra libraries. Plus, browsers support it natively through APIs like EventSource, keeping things simple on both server and client sides.
// src/lambdaHandler.ts
import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from "aws-lambda";
import { callClaudeStream } from "./handler";
export const streamHandler = async (
event: APIGatewayProxyEventV2
): Promise<APIGatewayProxyResultV2> => {
(global as any).callbackWaitsForEmptyEventLoop = false;
const body = event.body ? JSON.parse(event.body) : {};
const prompt = typeof body.prompt === "string" ? body.prompt : "Hello, Claude!";
const headers = {
"Content-Type": "text/event-stream; charset=utf-8",
"Cache-Control": "no-cache, no-transform",
Connection: "keep-alive",
};
const response: APIGatewayProxyResultV2 = {
statusCode: 200,
headers,
body: "",
isBase64Encoded: false,
};
const bedrockStream = await callClaudeStream(prompt);
const encoder = new TextEncoder();
const formatSSE = (data: string) => `data: ${data}\n\n`;
const sseWriter = new WritableStream({
async write(chunk) {
const text = new TextDecoder().decode(chunk);
const lines = text.split("\n").filter(Boolean);
for (const line of lines) {
try {
const obj = JSON.parse(line);
if (obj.type === "token") {
const sse = formatSSE(obj.text);
// @ts-ignore
}
} catch (e) {
// Ignore parsing errors
}
}
},
close() {
console.log("SSE stream closed by client or model.");
},
abort(err) {
console.error("SSE stream aborted:", err);
},
});
await bedrockStream.pipeTo(sseWriter);
return response;
};
When setting up SSE in Lambda, ensure the Content-Type is set to text/event-stream. This helps the browser understand that it’s receiving events, which it can handle using EventSource APIs. SSE offers a simpler alternative to WebSockets for one-way communication, easing server and client implementation.
Handling Errors and Limitations
Streaming with Bedrock has its own set of challenges. Developers need to be on their toes about potential issues:
- Token Limits: Bedrock imposes a cap on token generation per minute. To avoid throttling, a strategy for handling ThrottlingException errors is essential.
- Manual SSE Parsing: Bedrock gives you raw JSON lines, so you need to parse and format these for SSE. This means splitting lines and converting JSON to SSE-friendly data.
- Model Selection: Not every Bedrock model can stream, so you’ve got to check model compatibility in the Bedrock console.
- Cross-region Latency: Running your Lambda function in the same region as Bedrock can cut down latency, crucial for real-time needs.
Managing back-pressure is key for a steady streaming service. If a client disconnects, the server must stop sending data to avoid wasting resources. Keeping an eye on the TCP buffer and responding to writable stream readiness can prevent overloads. From what I’ve seen, setting up solid error handling and monitoring bolsters the service’s reliability significantly.
Practical Steps for Implementation
For those delving into Node.js 22 with Bedrock streaming, a few steps can streamline your efforts:
- Ensure your app is running on Node.js 22 to use the native fetch API.
- Install and set up the AWS SDK for JavaScript for Bedrock communications.
- Configure your Lambda function for SSE, paying attention to content type and connection settings.
- Implement error and back-pressure controls to keep your stream robust.
- Test your setup thoroughly to ensure it meets performance and compatibility standards.
Following these steps can greatly improve the responsiveness and user experience of your applications, especially those needing real-time interaction. Mastering stream lifecycle management and the nuances of token generation and delivery can make a significant difference in application efficiency and user satisfaction.
Sources
Streaming Claude Tokens from Bedrock with Node.js 22: SSE Made Simple
Every claim above was checked against this source before publishing. The analysis, the code and the opinions are mine.
Frequently asked
Why is streaming important for LLM applications?
Streaming allows for immediate token display, reducing latency and enhancing user experience by simulating real-time interactions.
What are the main benefits of using Node.js 22's native fetch API?
Node.js 22's native fetch API reduces the need for additional libraries, streamlines deployment, and integrates well with SSE.
What should I be cautious of when implementing streaming with Bedrock?
Be aware of token limits, manual SSE parsing requirements, and ensure your chosen model supports streaming.
How can I handle back-pressure in a streaming setup?
Monitor TCP buffer capacity and manage the writable stream's readiness to avoid overloading the stream and potential crashes.