Skip to main content

Streaming JSON Parser

Decode complete JSON documents or parse JSON as chunks arrive. streaming-json-parser provides a strict incremental parser with partial values and explicit parse states, alongside complete-document decoding, NDJSON, and selective extraction for Python.

CI PyPI Python versions License: MIT

python -m pip install streaming-json-parser

Quickstart: parse while the stream is still arriving

from streaming_json_parser import ParseStatus, StreamingJsonParser

parser = StreamingJsonParser()

partial = parser.feed(b'{"message":"hel')
assert partial.status is ParseStatus.PARTIAL
assert partial.value == {"message": "hel"}

complete = parser.feed(b'lo"}')
assert complete.status is ParseStatus.COMPLETE
assert complete.value == {"message": "hello"}

The parser resumes from its previous state on each chunk. It distinguishes EMPTY, PARTIAL, COMPLETE, and INVALID results; partial strings are available before the closing quote arrives. By default, .value refers to parser-owned state and may change after later chunks; pass copy_value=True to feed() when you need a retained snapshot.

Diagram showing a JSON string split across two chunks: the first produces a PARTIAL value and the second completes it

What it supports

  • Strict incremental parsing across arbitrary input chunks, with partial values and explicit statuses.
  • Complete JSON decoding, including reusable and workload-tuned decoders.
  • NDJSON decoding and streaming records.
  • Selective path extraction from complete JSON documents and NDJSON without always building every Python object.
  • Structural partial snapshots for callers that do not need unfinished string values. This is a separate finishing mode, not the strict incremental state machine.
  • Optional Rust acceleration through streaming-json-parser-native.

The Python implementation works without optional packages. The project is currently in beta while its public API settles.

Performance

These charts show three separate workloads from the checked-in benchmark snapshot. Bars report total process CPU time for each repeated batch; lower is better. Every measured result is shown. Values are generated from docs/benchmark-snapshot.json, and the environment, versions, workload sizes, and timing method are recorded in the benchmark report.

Complete JSON decoding

Decodes the same roughly 1 MB JSON object into a complete value. This is ordinary whole-document decoding; it does not measure incremental parsing.

Horizontal chart of complete JSON decoding times for streaming-json-parser APIs and alternative decoders; total CPU time for 20 iterations, lower is better

Complete-document selective extraction

Reads the same two object paths (meta.name and tail.count) from a 5,000-row JSON document. The full-decode baselines decode the document before accessing those paths.

Horizontal chart of complete-document selective extraction times for streaming-json-parser APIs and alternative approaches; total CPU time for 200 iterations, lower is better

NDJSON selective extraction

Reads row.id and row.value from each of 5,000 newline-delimited records. Full-decode baselines materialize each record before selecting its fields.

Horizontal chart of NDJSON selective extraction times for streaming-json-parser APIs and alternative approaches; total CPU time for 25 iterations, lower is better

These charts compare operations with the same output paths within each workload. Strict incremental parsers, structural partial finishers, and permissive JSON-repair tools have different semantics, so they are measured separately in the API scorecard and partial-strategy benchmark harness.

Real-world Python JSON benchmark corpus

This additional chart adapts the complete-document load workload and public datasets from the community-maintained TkTech JSON benchmark. It decodes six whole documents into ordinary Python values and checks every included decoder against json.loads before timing. Each panel has its own scale and reports input throughput; higher is better. This is a Python community benchmark, not a formal industry standard. The suite's SAX/event streaming cases are omitted because they do not produce the same output as this parser.

Grouped horizontal bars compare complete-load throughput on six public JSON corpus files across streaming-json-parser APIs and common Python decoder libraries

Results vary by dataset and decoder; compare the per-file values, dataset hashes, package versions, methodology, and upstream revision in the community corpus report and JSON snapshot. For an already-complete document, use a complete-document API. Sending it through StreamingJsonParser.feed() also performs incremental state handling, so it is not a substitute for decode_complete_json(). These corpus timings are separate from the generated synthetic workloads above.

Choose an API

Workload API Notes
One complete JSON document decode_complete_json(data) Returns a regular Python value.
Repeated complete-document decoding make_tuned_complete_json_decoder(...) Calibrates against a representative sample and payload size.
JSON arriving in chunks StreamingJsonParser Strict resumable parser; inspect ParseResult.status and .value after each feed().
Newline-delimited records decode_ndjson(data) or StreamingJsonParser(framing="ndjson") Call finish() to consume a final record without a newline.
Incomplete prefix; unfinished strings can be omitted decode_structural_partial_json(prefix) Structural finisher; not equivalent to strict incremental parsing.
A few fields from JSON or NDJSON make_tuned_json_path_extractor(..., framing="single" or "ndjson") Reuse the extractor for a stable workload.
Typed records make_ndjson_decoder(record_type=...) Optional typed decoding through msgspec.

There is no single best backend for every input. The tuned factories can benchmark compatible backends once during setup when given a representative sample and payload_size_hint.

Common operations

Decode a complete document

from streaming_json_parser import decode_complete_json

value = decode_complete_json(b'{"name":"example","ok":true}')

For large read-only payloads, decode_complete_json_view() can return a view backed by simdjson; use it only when proxy/view semantics are suitable for your application.

Read NDJSON records

from streaming_json_parser import decode_ndjson

records = decode_ndjson(b'{"id":1}\n{"id":2}\n')

The stateful parser also supports framing="ndjson" and poll_many() to drain complete records as they become available.

Finish a structural partial value

Structural partial mode is useful when a caller has an incomplete prefix and needs completed objects or arrays from it. By default, it omits an unfinished trailing string; use trailing_strings=True or partial_mode="structural_trailing_strings" when that text must be retained. It may complete scalar prefixes differently from the strict parser.

from streaming_json_parser import decode_structural_partial_json

value = decode_structural_partial_json('{"items":[1,2')
assert value == {"items": [1, 2]}

Optional acceleration

Install the Rust extension separately when a compatible wheel is available:

python -m pip install streaming-json-parser-native

The native package is optional. Backend-specific packages such as msgspec, orjson, and simdjson are also optional; APIs fall back to the Python implementation where applicable.

Reproduce the benchmarks

The benchmark snapshot includes the date, source revision and dirty-state flag, Python and platform details, processor and architecture, installed benchmark-package versions, native-extension availability, payload sizes, record counts, and selected paths. The methodology records its clock, warm-up, sample count, and repetitions.

To run the benchmark with the optional alternatives installed, then regenerate all reports and SVGs:

python -m pip install -e '.[test,benchmark,accelerated]'
python -m pip install 'streaming-json-parser-native==0.2.0'
make benchmark-artifacts

The native package is separate from the Python extras. Install it to reproduce the snapshot's native benchmark rows; the snapshot records the exact optional package versions used.

To run the adapted whole-document benchmark against the public corpus, clone the benchmark data and pass its data/ directory. This is separate from make benchmark-artifacts so the everyday benchmark does not download external files:

git clone --depth 1 https://github.com/TkTech/json_benchmark.git /tmp/tktech-json-benchmark
make benchmark-community-corpus COMMUNITY_JSON_CORPUS_DIR=/tmp/tktech-json-benchmark/data
make verify-community-benchmark-artifacts

To verify generated Markdown, scorecard, charts, and the current benchmark results against the committed snapshot:

make verify-benchmark-artifacts

Verification checks generated files against the authoritative JSON snapshot and reruns the same benchmark slices. Timing checks allow shared machine slowdowns, but detect large per-implementation regressions. For meaningful comparisons, use the same dependency versions and a similar machine; compare the provenance fields in the snapshot.

Development

python -m pip install -e '.[test]'
python -m pytest -q

See contributing guidance, the changelog, the current API scorecard, open issues, and manual GitHub settings follow-up.

License

MIT. See LICENSE.

Release files for streaming-json-parser 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for streaming-json-parser 0.2.1
File Size Uploaded
streaming_json_parser-0.2.1.tar.gz 58.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for streaming-json-parser 0.2.1
File Interpreter ABI Platform
streaming_json_parser-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 89.8 kB

Release files / streaming_json_parser-0.2.1.tar.gz

Download URL streaming_json_parser-0.2.1.tar.gz
Size 58.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d75a29e7660c4cdd7bdc99d1be61ef8c33fa4b4094aa10b3275a8ba6fb1aadcb
BLAKE2b-256 checksum
How to use checksums
512398fb0336ad4e12130ad84005f9cb35fadf35f54a826c765a5e8b53ab9e57
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / streaming_json_parser-0.2.1-py3-none-any.whl

Download URL streaming_json_parser-0.2.1-py3-none-any.whl
Size 31.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fe163fcbde52d1c8a6af44be5985e48b00de32065c4c8767c28f2aec27f478ea
BLAKE2b-256 checksum
How to use checksums
f7ed02d49654eff6dc6dd1b11a9f2aeaaf0330bd3609153c070fe86bdf15b746
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.2

2 release files

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page