Stream typed, validated partial objects out of an LLM token stream. Render structured output as it arrives.
When you ask an LLM for JSON, the user waits for the whole object before anything renders.
Existing partial-JSON parsers (partial-json-parser, parse-json-stream) fix the parsing half —
they hand you a half-built unknown. They don't tell you which fields are safe to use yet,
and they don't give you types.
streamschema is the typed layer on top: you give it a Zod schema, it consumes the token stream,
and it yields a sequence of progressively-complete, typed snapshots — each one telling you
exactly which fields are settled, which are still streaming, and which are missing. So your UI can
paint title the instant it closes, while body is still arriving.
- Schema-driven — define the shape with Zod; every yielded snapshot is typed as a deep-partial
of your schema. No casting
any. - Field-completion tracking — each snapshot carries a
statusmap:complete|streaming|pendingper field, so the UI knows what's safe to commit. - Tolerant parsing — handles unterminated strings, trailing commas, and markdown code fences mid-stream; never throws on an incomplete chunk.
- Backpressure-friendly — an async iterable that works with Node streams,
ReadableStream, Bun, Deno, and Cloudflare Workers. - Final validation — when the stream ends, runs full Zod validation so you get a real, parsed, guaranteed-valid object (or a typed error).
npm install streamschema zodimport { streamSchema } from "streamschema";
import { z } from "zod";
const Recipe = z.object({
title: z.string(),
steps: z.array(z.string()),
});
const stream = streamSchema(Recipe, llmTokenStream); // llmTokenStream: AsyncIterable<string>
for await (const snapshot of stream) {
// snapshot.value: DeepPartial<Recipe>, snapshot.status: per-field completion
if (snapshot.status.title === "complete") render(snapshot.value.title);
renderSteps(snapshot.value.steps ?? []); // grows as each step closes
}
const recipe = await stream.final(); // fully validated Recipe — or throws typed ValidationErrorRoadmap: tolerant tokenizer → schema projection + status → final validation → React
useStreamSchema hook.
MIT