Skip to content
GigadriveDocs

Streaming

Node and Bun Functions stream response bodies to the client as they are produced, with no flag to set.

A Node or Bun Function streams by default. Whatever your code writes to the response goes out as it is written, so server-sent events, React Server Component payloads and long JSON exports reach the browser progressively instead of landing in one block at the end.

What it looks like

// api/events.js
import http from 'node:http';

const server = http.createServer((req, res) => {
  res.writeHead(200, {
    'content-type': 'text/event-stream',
    'cache-control': 'no-store',
  });

  let tick = 0;
  const timer = setInterval(() => {
    tick += 1;
    res.write(`data: ${JSON.stringify({ tick, at: new Date().toISOString() })}\n\n`);
    if (tick === 10) {
      clearInterval(timer);
      res.end();
    }
  }, 1000);

  req.on('close', () => clearInterval(timer));
});

server.listen(3000);
version: 4

functions:
  api/events.js:
    runtime: node-22
    max_duration: 60

routes:
  - source: ^/events$
    destination: /api/events.js

Each res.write is flushed on its own rather than buffered until the handler returns, so the client sees the first event about a second after connecting. Gigadrive Network captures the server your code creates and assigns it a port, so the number you pass to listen is ignored.

Response headers

The response body passes through untouched. Caching and compression headers are handled at the edge:

  • A streamed response you want cached needs an explicit cache-control. A Function that sets none gets cache-control: no-store.
  • Compression is negotiated at the edge, not in your Function. Your code never sees the client's accept-encoding, and the CDN compresses the response and sets its own content-encoding and content-length. Write plain bytes.

Where a stream ends

Set max_duration to something above the longest stream you expect, and close the stream from your own code when a client disconnects. In the example, req.on('close', ...) stops the interval when a browser navigates away; without it the Function keeps producing events nobody reads until the deadline fires.

A WebSocket is the better fit when the client needs to send as well as receive.