mrkeyoor.com_
Wed 05 Aug 19:52 UTC
npmAI / MLupdated 05 Aug 2026

partial-json

partial-json parses JSON strings that are cut off mid-stream. When an LLM streams a JSON response token by token, JSON.parse fails on every chunk until the very last one; partial-json's parse function instead returns the best complete value it can build from what has arrived so far, so you can render structured data live while it streams. An Allow bitmask controls which types may be incomplete: with STR a half-finished string is returned as-is, without it the parser waits for the closing quote. It is a small pure-JavaScript library with zero dependencies and both CJS and ESM builds.

Verdict

The standard small tool for one specific job: showing structured LLM output while it streams, which explains 5M+ weekly downloads on 243 stars. Use it for that; for repairing invalid JSON or parsing huge streams pick a different tool.

API stability4/5Still 0.x, but the surface is two exports (parse and Allow) that have not changed in years; there is very little API to break.
Docs3/5The README covers the whole API with clear examples and there is a live demo, but that is all the documentation there is; edge-case behavior you learn by experiment.
Maintenance3/5Last push June 2026 and only 5 open issues, but it is a small single-org project with an infrequent release cadence; low activity is partly low surface area.
Ecosystem3/5Massive incidental reach because AI SDKs and LLM apps pull it in, with a matching Python implementation, but there are no plugins or tooling around it and few third-party resources.

Use it if

  • You stream JSON from an LLM (tool arguments, structured output) and want to update the UI on every chunk instead of waiting for the final token
  • You want JSON.parse-compatible behavior on complete input with graceful handling of truncated input, in one function
  • You need control over what may be partial, for example allow half-open objects but suppress half-finished string values so users never see cut-off text
  • You need to salvage a value from a response that hit a max-token limit and ended mid-object
Skip it if

Setup reality

npm i partial-json and you are done: zero dependencies, TypeScript types included, works in Node and browsers with both require and import. The things to internalize are behavioral, not install-related. parse defaults to Allow.ALL, which will happily return half-written strings and numbers, so decide your bitmask deliberately. You also still own the streaming loop: accumulate chunks into one string yourself and call parse on each update, and wrap calls in try/catch because a chunk boundary can still leave text the parser considers malformed rather than merely incomplete.

Patterns

Parse complete JSON like JSON.parseparse-complete-json

import { parse } from "partial-json";

const result = parse('{"key": "value"}');
console.log(result); // { key: 'value' }

On complete input parse behaves like JSON.parse, so you can use one code path for both mid-stream and final payloads.

Parse a truncated string with defaultsparse-truncated-json

import { parse } from "partial-json";

const result = parse('[{"key1": "value1", "key2": ["value2');
console.log(result);
// [ { key1: 'value1', key2: [ 'value2' ] } ]

The default allowance is Allow.ALL, so everything including half-finished strings is returned; pass a bitmask if that is too eager.

Choose which types may be incompleterestrict-partial-types

import { parse, Allow } from "partial-json";

parse('{"key": "v', Allow.STR | Allow.OBJ);
// { key: 'v' }

parse('{"key": "v', Allow.OBJ);
// {}  (string not closed, so the pair is withheld)

Types not in the mask only appear once the parser is sure they are complete; note the unclosed object itself needs OBJ in the mask.

Render streamed LLM JSON incrementallystream-llm-output

import { parse, Allow } from "partial-json";

let buffer = "";
for await (const chunk of llmStream) {
  buffer += chunk;
  try {
    render(parse(buffer, Allow.OBJ | Allow.ARR | Allow.STR));
  } catch {
    // chunk boundary left unparseable text; wait for more
  }
}

You accumulate the full string and reparse each time; that is fine for typical LLM response sizes but is quadratic over very long streams.

Suppress half-finished string values in a UIhide-partial-strings

import { parse, Allow } from "partial-json";

const safe = parse(buffer, Allow.OBJ | Allow.ARR);
// string fields only appear after their closing quote

Useful when showing a cut-off URL or sentence would confuse users; keys and completed values still stream in as they finish.

Import allowance flags without the Allow objectimport-flags-directly

import { parse, STR, OBJ, ARR } from "partial-json";

const result = parse(buffer, STR | OBJ | ARR);

Each Allow property is also a named export; the values are plain numbers combined with bitwise OR.

Handle NaN and Infinity literalsparse-special-values

import { parse } from "partial-json";

parse("-Inf");   // -Infinity
parse("NaN");    // NaN

These are not valid JSON, but Python's json.dumps emits them, so the parser accepts them; gate with Allow.SPECIAL if you do not want partial forms.

Distinguish truncated from malformed inputcatch-malformed-json

import { parse } from "partial-json";

try {
  parse("wrong");
} catch (e) {
  console.log(e.name); // MalformedJSON
}

Truncated JSON returns a value; genuinely invalid JSON throws MalformedJSON. Do not use this library expecting repair of bad syntax.

Allow partial literals like tru and nulparse-partial-atoms

import { parse, Allow } from "partial-json";

parse('[tru', Allow.ARR | Allow.BOOL); // [true]
parse('[nul', Allow.ARR | Allow.NULL); // [null]

With the matching atom flag the parser commits to the only literal the prefix can become; without it the element is omitted until complete.

Use the convenience flag groupsgroup-flags

import { parse, Allow } from "partial-json";

Allow.COLLECTION; // ARR | OBJ
Allow.ATOM;       // strings, numbers, booleans, null, specials
Allow.ALL;        // everything (the default)

parse(buffer, Allow.COLLECTION);

Allow.COLLECTION is the common choice for UIs: structure streams in live while every scalar value waits until it is complete.

Alternatives

PackageRegistryPick it when
jsonrepairnpmYour input is broken JSON (quotes, commas, comments), not just truncated JSON, and you want it fixed into valid output.
best-effort-json-parsernpmYou want maximally forgiving parsing of messy partial JSON without configuring what may be incomplete.
@streamparser/jsonnpmYou need true incremental SAX-style parsing of large JSON streams without reparsing from the start.