Skip to main content
@knitkit/edge assembles a complete page at the edge from independent HTML fragments — each owned by a different team, built with a different framework (or no framework at all). It fetches all fragments in parallel, streams them into the host template in document order, and injects a negotiated import map before </head> so any client-side modules hydrate correctly. Because every fragment renders its own HTML, there is no shared React instance to coordinate and no “invalid hook call” risk. The package runs wherever the Web Fetch and Streams APIs are available: Cloudflare Workers, Deno Deploy, Vercel Edge Functions, and Node.js 18+.

Install

Concepts

Fragment placeholders

You mark insertion points in your host HTML template with <knitkit-fragment> custom elements:
Use the self-closing form when you have no meaningful fallback:
Each placeholder’s name attribute maps to a Fragment object in the fragments array you pass to composeStream.

The Fragment type

Step-by-step

API overview

composeStream(options)

Returns a ReadableStream<Uint8Array> that flushes template text immediately and streams each fragment in document order as its fetch resolves. Use this when you need direct control over the stream — for example, to pipe it into a Node http.ServerResponse.

composeResponse(options, init?)

Wraps composeStream in a Response with content-type: text/html; charset=utf-8. The typical return value from an edge handler. You can pass a second ResponseInit argument to add extra headers or override the status code.

compose(options)

Buffers the entire composed page into a single string. Useful for testing, pre-rendering to a CDN, or any context where you need the full HTML before proceeding.

parseTemplate(template)

Splits the template into an ordered array of { type: "text", value } and { type: "fragment", name, fallback } segments. Exported for unit testing your templates in isolation — you can assert on the parse tree without needing a network.

serializeImportMap(map)

Re-exported from @knitkit/edge for cases where you manage the import-map tag yourself instead of passing importMap to composeStream.

Graceful degradation

When a fragment fetch fails — network error, non-2xx status, or a timeout you set via AbortSignal in init — composeStream falls back to the placeholder’s inner HTML. The page still renders completely; only the affected section shows the fallback content. Provide a custom error handler to override the default fallback:
If you do not supply onError, the fallback is the placeholder’s inner HTML. If the placeholder is self-closing (no inner HTML), knitkit emits an HTML comment so you can see the failure in the page source without a visible UI error.

Real gateway example

The following is drawn from examples/edge-composition/gateway.mjs in the knitkit repo. It adapts the Web ReadableStream to Node’s http module for local development — on a real edge runtime you would return composeResponse directly.
Fragment servers must respond with CORS headers (Access-Control-Allow-Origin) when the gateway and fragment origins differ, or when you are running the gateway on a real edge platform that fetches from a different origin. Add { "Access-Control-Allow-Origin": "*" } (or a specific origin) to every fragment server’s response headers. In production, scope the header to your gateway’s hostname rather than using the wildcard.