Skip to main content

Streaming

Overview​

docxio supports streaming .docx bytes as a ReadableStream, which is useful for HTTP responses where you want to start sending data before the entire document is assembled.

renderToStream​

import { renderToStream } from "docxio";

const stream = renderToStream(
<document title="Streamed Report">
<section>
<paragraph><run>Hello from a stream!</run></paragraph>
</section>
</document>
);

The returned stream is a standard web ReadableStream<Uint8Array>.

HTTP response (Bun)​

import { renderToStream } from "docxio";

Bun.serve({
fetch(req) {
const doc = (
<document title="Report">
<section>
<paragraph><run>Generated on the fly.</run></paragraph>
</section>
</document>
);

const stream = renderToStream(doc);

return new Response(stream, {
headers: {
"Content-Type":
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"Content-Disposition": 'attachment; filename="report.docx"',
},
});
},
});

HTTP response (Node.js / Express)​

import { renderToReadableStream } from "docxio";
import { Readable } from "node:stream";

app.get("/report.docx", async (req, res) => {
const doc = (
<document title="Report">
<section>
<paragraph><run>Server-generated document.</run></paragraph>
</section>
</document>
);

const webStream = renderToReadableStream(doc);
const nodeStream = Readable.fromWeb(webStream);

res.setHeader(
"Content-Type",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
);
res.setHeader("Content-Disposition", 'attachment; filename="report.docx"');
nodeStream.pipe(res);
});

When to use streaming​

Streaming is beneficial when:

  • The document is large and you want to reduce time-to-first-byte
  • You are serving documents over HTTP and want to avoid buffering the entire file in memory
  • You are piping directly to a file or another stream consumer

For small documents or when you need the complete bytes (e.g., to calculate a hash), use render() instead.