Chunks in web streams are fundamental data units that can be of many different types depending on the content, such as String for text or Uint8Array for binary files. While standard Function responses contain full payloads of data processed on the server, streamed responses typically send data in chunks over time.
To do this, you create a ReadableStream and add a data source, then transform the stream's data chunks before they're read by the client. Finally, you write stream the data chunk by chunk as a Function response.
Jump to the full example to see the finished recipe.
Create a ReadableStream and add a data source. In this case, you'll create your own data by encoding text with TextEncoder:
// TextEncoder objects turn text content// into streams of UTF-8 characters.// You'll add this encoder to your streamconst encoder = new TextEncoder();// This is the stream object, which clients can read from// when you send it as a Function responseconst readableStream = new ReadableStream({ // The start method is where you'll add the stream's content start(controller) { const text = 'Stream me!'; // Queue the encoded content into the stream controller.enqueue(encoder.encode(text)); // Prevent more content from being // added to the stream controller.close(); },});// TextEncoder objects turn text content// into streams of UTF-8 characters.// You'll add this encoder to your streamconst encoder = new TextEncoder();// This is the stream object, which clients can read from// when you send it as a Function responseconst readableStream = new ReadableStream({ // The start method is where you'll add the stream's content start(controller) { const text = 'Stream me!'; // Queue the encoded content into the stream controller.enqueue(encoder.encode(text)); // Prevent more content from being // added to the stream controller.close(); },});You then need to transform the stream's data chunks before they're read by the client. First, you'll decode the chunks with TextDecoder, then transform the text to uppercase before encoding the text again:
// TextDecoders can decode streams of// encoded content. You'll use this to// transform the streamed content before// it's read by the clientconst decoder = new TextDecoder();// before they're read in the client// TransformStreams can transform a stream's chunksconst transformStream = new TransformStream({ transform(chunk, controller) { // Decode the content, so it can be transformed const text = decoder.decode(chunk); // Make the text uppercase, then encode it and // add it back to the stream controller.enqueue(encoder.encode(text.toUpperCase())); },});// TextDecoders can decode streams of// encoded content. You'll use this to// transform the streamed content before// it's read by the clientconst decoder = new TextDecoder();// TransformStreams can transform a stream's chunks// before they're read in the clientconst transformStream = new TransformStream({ transform(chunk, controller) { // Decode the content, so it can be transformed const text = decoder.decode(chunk); // Make the text uppercase, then encode it and // add it back to the stream controller.enqueue(encoder.encode(text.toUpperCase())); },});Finally, write stream the data chunk by chunk as a Function response:
// Finally, send the streamed response. Result:// "STREAM ME!" will be displayed in the clientreturn new Response(readableStream.pipeThrough(transformStream), { headers: { 'Content-Type': 'text/html; charset=utf-8', },});// Finally, send the streamed response. Result:// "STREAM ME!" will be displayed in the clientreturn new Response(readableStream.pipeThrough(transformStream), { headers: { 'Content-Type': 'text/html; charset=utf-8', },});The final file will look like this:
// This method must be named GETexport async function GET() { // TextEncoder objects turn text content // into streams of UTF-8 characters. // You'll add this encoder to your stream const encoder = new TextEncoder(); // This is the stream object, which clients can read from // when you send it as a Function response const readableStream = new ReadableStream({ // The start method is where you'll add the stream's content start(controller) { const text = 'Stream me!'; // Queue the encoded content into the stream controller.enqueue(encoder.encode(text)); // Prevent more content from being // added to the stream controller.close(); }, });
// TextDecoders can decode streams of // encoded content. You'll use this to // transform the streamed content before // it's read by the client const decoder = new TextDecoder(); // TransformStreams can transform a stream's chunks // before they're read in the client const transformStream = new TransformStream({ transform(chunk, controller) { // Decode the content, so it can be transformed const text = decoder.decode(chunk); // Make the text uppercase, then encode it and // add it back to the stream controller.enqueue(encoder.encode(text.toUpperCase())); }, });
// Finally, send the streamed response. Result: // "STREAM ME!" will be displayed in the client return new Response(readableStream.pipeThrough(transformStream), { headers: { 'Content-Type': 'text/html; charset=utf-8', }, });}// This method must be named GETexport async function GET() { // TextEncoder objects turn text content // into streams of UTF-8 characters. // You'll add this encoder to your stream const encoder = new TextEncoder(); // This is the stream object, which clients can read from // when you send it as a Function response const readableStream = new ReadableStream({ // The start method is where you'll add the stream's content start(controller) { const text = 'Stream me!'; // Queue the encoded content into the stream controller.enqueue(encoder.encode(text)); // Prevent more content from being // added to the stream controller.close(); }, });
// TextDecoders can decode streams of // encoded content. You'll use this to // transform the streamed content before // it's read by the client const decoder = new TextDecoder(); // TransformStreams can transform a stream's chunks // before they're read in the client const transformStream = new TransformStream({ transform(chunk, controller) { // Decode the content, so it can be transformed const text = decoder.decode(chunk); // Make the text uppercase, then encode it and // add it back to the stream controller.enqueue(encoder.encode(text.toUpperCase())); }, });
// Finally, send the streamed response. Result: // "STREAM ME!" will be displayed in the client return new Response(readableStream.pipeThrough(transformStream), { headers: { 'Content-Type': 'text/html; charset=utf-8', }, });}If you're not using a framework, you must either add "type": "module" to your package.json or change your JavaScript Functions' file extensions from .js to .mjs
Build your app and visit localhost:3000/api/chunk-example. You should see the text "STREAM ME!" in the browser.
Run your app locally and visit localhost:3000/api/data-chunks. You should see the text "STREAM ME!" in the browser.
See understanding chunks to learn more.