Skip to content

Latest commit

 

History

History
142 lines (118 loc) · 7.12 KB

COMPARISON.md

File metadata and controls

142 lines (118 loc) · 7.12 KB

Comparison

How the Stanza X12 streaming parser compares with the most established open-source Node parsers, and where it does and does not compete with commercial EDI products.

Method

  • File: 500.5 MB of synthetic 837P claims, 255,000 transactions, ~1,963 bytes per transaction, generated by bin/generate.mjs (seed 42).
  • Hardware: Intel Core i7-10700K @ 3.80 GHz, 31 GiB RAM, Linux 7.2.5, Node v26.8.2.
  • Each parser runs in a fresh process, sequentially, never in parallel.
  • Output is discarded while parsing: the measurement is parse cost, not retention policy. items counts emitted units (Stanza emits parsed transactions, the libraries emit raw segments).
  • peak_heap_mb samples process.memoryUsage().heapUsed every 25 ms. The "capped" run additionally enforces --max-old-space-size=25, which aborts the process if old-space allocation exceeds the bound.
  • Versions: node-x12@1.7.1, x12-parser@1.3.0.

Reproduce:

npm run build
node bin/generate.mjs --transactions 255000 --claims 5 --out data/claims.x12
node bin/compare.mjs --file data/claims.x12 --cap 25
node bin/compare.mjs --file data/claims.x12

Results

Capped at 25 MB old space:

parser mode result wall items peak heap
Stanza streaming, domain parsing ok 14.2 s 255,001 transactions 22.2 MB
node-x12 streaming, lax ok 20.3 s 20,655,000 segments 26.2 MB
x12-parser streaming ok 39.2 s 20,655,000 segments 32.8 MB
node-x12 streaming, strict fails on valid input - - -

Uncapped (default V8 heap):

parser mode result wall items peak heap
Stanza streaming, domain parsing ok 13.4 s 255,001 transactions 94.7 MB
node-x12 streaming, lax ok 13.6 s 20,655,000 segments 35.4 MB
x12-parser streaming ok 32.3 s 20,655,000 segments 32.9 MB

What the numbers actually say

  • On raw throughput with memory to spare, Stanza and node-x12 are statistically tied. "Fastest parser" would be an overclaim.
  • Under a hard 25 MB ceiling, Stanza holds its uncapped speed (14.2 s) while node-x12 slows by 50% (13.6 s to 20.3 s) under GC pressure and x12-parser is roughly 2.7x slower than Stanza.
  • Stanza emits 255k parsed transaction frames; the libraries emit 20.65M raw segment objects. Stanza does more semantic work per unit and produces 81x fewer objects for the consumer to handle.
  • Stanza's uncapped heap is higher because it lets V8 grow when allowed. The capped run is the stronger evidence: the same workload completes inside a 25 MB old-space bound.

Fairness notes

  • The parsers do not do identical work. Stanza maps 837P claims into typed frames with SNIP element checks (for example NPI Luhn validation). node-x12 and x12-parser build generic segment trees. That difference is the point: more work, fewer objects, same or better speed.

  • node-x12 strict streaming mode throws on a valid single-envelope file: X12 Standard: An EDI document must contain at least one functional group. Its stream path pushes segments without building the interchange object model and then validates that model at flush. Measurements above use lax mode. To reproduce the strict failure:

    node -e "const {X12Parser}=require('node-x12');const fs=require('fs');
    const p=new X12Parser(true);fs.createReadStream('data/claims.x12').pipe(p)
      .on('data',()=>{}).on('error',e=>console.log(e.message));"
  • node-x12's documented large-file flow retains every emitted segment and calls getInterchangeFromSegments at the end. We discard output for every parser, because retention is a consumer decision, not a parsing cost. Retaining 20.65M segment objects would change the memory picture substantially.

  • Single machine, single corpus, synthetic data. Throughput varies with CPU and Node version; run the commands above to measure your own environment.

Feature matrix

Stanza parser node-x12 x12-parser Commercial EDI platforms
License BSL 1.1 (converts to Apache 2.0) MIT MIT Proprietary
Model Hosted API, parser source visible Library Library Platform / managed service
Transaction coverage 837P, 835, 270/271 Generic X12 structure Generic X12 structure Broad: 837/835/270/271/276/277/820/834/997...
Domain validation 837/835/271 field mapping, SNIP element checks (NPI Luhn and more) Structural only Structural only Full TR3 situational rules, SNIP levels, acknowledgments
Streaming Yes, bounded memory Yes (see caveats) Yes Varies
Edge/serverless Yes, designed for V8 isolates Runtime-agnostic library Runtime-agnostic library Usually server-side
Typed SDKs TypeScript, Python, C#, Rust on four registries TypeScript types TypeScript types Varies
MCP / agent tooling Yes (@stanzaapi/mcp) No No Rare
Trading-partner connectivity No No No Yes: AS2, SFTP, VAN, clearinghouse networks
Mapping / translation No Library-level mapping No Yes: visual mapping, transformation pipelines
Support / compliance programs Self-serve Community Community Enterprise support, BAAs, audits

Where Stanza does not compete

  • Connectivity: AS2, SFTP, VANs, and clearinghouse networks are how EDI actually moves between partners. Stanza parses and validates payloads; it does not transport them.
  • Mapping and translation: enterprise suites offer visual mapping, code lists, and transformation pipelines. Stanza hands you typed JSON.
  • Full spec validation: TR3 situational rules, acknowledgment generation (997/999), and complete SNIP levels are not implemented. Validation is element-level, not claim-adjudication-level.
  • Coverage: four healthcare transaction sets, not twenty.
  • Ecosystem: one maintainer, no third-party plugin ecosystem, no enterprise support desk, no independent security audit.

Honest drawbacks of the Stanza parser itself

  • It does not validate ST02/SE02 transaction control consistency. node-x12 catches this in strict mode; Stanza currently accepts it. This surfaced while building this comparison and is tracked in the adversarial suite (structure.st-se-control-mismatch).
  • The BSL license is source-available, not OSI open source. Libraries above are MIT; if license permissiveness is your priority, they win.
  • Benchmarks are single-machine and synthetic. They are reproducible, not independently replicated.
  • The tokenizer avoids regular expressions, which is good engineering but not a novel technique. Every high-performance parser does this.

Advantages that survived scrutiny

  • Verified speed under a hard memory ceiling, which is the constraint that breaks parsers in serverless and edge runtimes.
  • Domain parsing (typed 837/835/271 output) at library-level speed.
  • Distribution beyond one language: typed clients on npm, PyPI, NuGet, and crates.io, plus an MCP server.
  • Breadth across standards in one platform: X12 alongside ISO 20022, PEPPOL, GS1, DSCSA, and others.
  • A public benchmark and adversarial test suite, which none of the comparison targets publish.