diff --git a/README.md b/README.md
index 260e9a05..b8fa120c 100644
--- a/README.md
+++ b/README.md
@@ -613,6 +613,44 @@ app.get(layout.pathname(), (req, res) => {
});
```
+### res.podiumStream(...templateArguments)
+
+Method on the `http.ServerResponse` object for streaming HTML to the browser. This function returns a `ResponseStream` object that can then be used to push out HTML to the browser in chunks using its .send() function. Once streaming is finished, the .done() function must be called to close the stream.
+
+```js
+const stream = res.podiumStream();
+stream.send(`
HTML chunk 1
`);
+stream.send(`
HTML chunk 2
`);
+stream.done();
+```
+
+The Podium document template will still be used. When you call res.podiumStream(), the document head will be sent to the browser immediately. Once the .done() function is called, the closing part of the template will be sent before the stream is closed out.
+
+Note that any arguments passed to .podiumStream(...args) will be passed on to the layout's document template.
+
+**Working with assets**
+
+When working with assets, its important to wait for podlets to have sent their assets to the layout via 103 early hints. Use the incoming.hints `complete` event for this. Wait for assets to be ready, set assets on the incoming object and then call res.podiumStream.
+
+```js
+const incoming = res.locals.podium;
+const headerFetch = p1Client.fetch(incoming);
+const footerFetch = p2Client.fetch(incoming);
+
+incoming.hints.on('complete', async ({ js, css }) => {
+ incoming.js = js;
+ incoming.css = css;
+
+ const stream = res.podiumStream();
+ const [header, footer] = await Promise.all([
+ headerFetch,
+ footerFetch,
+ ]);
+ stream.send(`${header}...`);
+ stream.done();
+});
+```
+
### .client
A property that exposes an instance of the [@podium/client] for fetching content
diff --git a/example/streaming/podlets/content.js b/example/streaming/podlets/content.js
new file mode 100644
index 00000000..c54d2a76
--- /dev/null
+++ b/example/streaming/podlets/content.js
@@ -0,0 +1,61 @@
+import Podlet from '@podium/podlet';
+import express from 'express';
+
+const podlet = new Podlet({
+ name: 'content-podlet',
+ version: Date.now().toString(),
+ pathname: '/',
+ useShadowDOM: true,
+});
+
+podlet.css({ value: 'http://localhost:6103/css', strategy: 'shadow-dom' });
+
+const app = express();
+
+app.use(podlet.middleware());
+
+app.get('/manifest.json', (req, res) => {
+ res.send(podlet);
+});
+
+app.get('/css', (req, res) => {
+ res.set('Content-Type', 'text/css');
+ res.send(`
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ .content {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+ font-family: Verdana, serif;
+ font-weight: 400;
+ font-style: normal;
+ }
+ h1 {
+ color: #136C72;
+ }
+ `);
+});
+
+app.get('/', async (req, res) => {
+ res.set('Content-Type', 'text/html');
+ res.sendHeaders();
+
+ await new Promise((res) => setTimeout(res, 2200));
+
+ res.podiumSend(`
+
+
Podlets fetched and composed, on demand, just for you
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.