Skip to content

Migrating from 1.x to 2.x

Eugene Lazutkin edited this page May 29, 2026 · 4 revisions

This page covers migrating from stream-json 1.x to 2.x. The main theme is a shift from class-based modules to functional factories built on stream-chain 3.4.x. Source files were also renamed PascalCase → kebab-case in 2.0 to normalize the layout — see Import paths below for the full mapping. Update any require() / import path that referenced a PascalCase file in 1.x.

If you feel that some fine points are missing or covered incorrectly, please suggest an edit.

Overview of changes

Area 1.x 2.x
Module style Class-based (new Stringer(options)) Functional factories (stringer(options))
File names PascalCase (StreamArray.js, Stringer.js, …) kebab-case (stream-array.js, stringer.js, …)
.make() Available on all rewritten modules Removed — use factory directly or .asStream()
instanceof stream instanceof Stringer Not available for rewritten modules
Utf8Stream Active Deprecated — use fixUtf8Stream from stream-chain
stream-chain 3.x 3.4.x required
TypeScript Bundled .d.ts Updated to function+namespace pattern

Import paths

Every PascalCase source file was renamed to kebab-case in 2.0. The user-facing stream-json/... path is the same shape — only the file name's casing changed. For each rewritten module the default-export identity also changed from a PascalCase class to a camelCase factory function (with the notable exception of Assembler, which kept its class shape — see the table below).

1.x path / default export 2.x path / default export
stream-json/Parser.js / Parser (class) stream-json/parser.js / parser (function)
stream-json/Assembler.js / Assembler (class) stream-json/assembler.js / Assembler (class, kept)
stream-json/Disassembler.js / Disassembler (class) stream-json/disassembler.js / disassembler (function)
stream-json/Stringer.js / Stringer (class) stream-json/stringer.js / stringer (function)
stream-json/Emitter.js / Emitter (class) stream-json/emitter.js / emitter (function)
stream-json/filters/Filter.js / Filter stream-json/filters/filter.js / filter
stream-json/filters/Pick.js / Pick stream-json/filters/pick.js / pick
stream-json/filters/Replace.js / Replace stream-json/filters/replace.js / replace
stream-json/filters/Ignore.js / Ignore stream-json/filters/ignore.js / ignore
stream-json/filters/FilterBase.js / FilterBase stream-json/filters/filter-base.js / filterBase
stream-json/streamers/StreamArray.js / StreamArray stream-json/streamers/stream-array.js / streamArray
stream-json/streamers/StreamObject.js / StreamObject stream-json/streamers/stream-object.js / streamObject
stream-json/streamers/StreamValues.js / StreamValues stream-json/streamers/stream-values.js / streamValues
stream-json/streamers/StreamBase.js / StreamBase stream-json/streamers/stream-base.js / streamBase
stream-json/jsonl/Parser.js / JsonlParser stream-json/jsonl/parser.js / jsonlParser
stream-json/jsonl/Stringer.js / JsonlStringer stream-json/jsonl/stringer.js / jsonlStringer
stream-json/utils/Batch.js / Batch (class) stream-json/utils/batch.js / batch (function)
stream-json/utils/Verifier.js / Verifier (class) stream-json/utils/verifier.js / verifier (function)
stream-json/utils/Utf8Stream.js / Utf8Stream stream-json/utils/utf8-stream.js / Utf8Stream (deprecated — see below)
stream-json/utils/withParser.js / withParser stream-json/utils/with-parser.js / withParser
stream-json/utils/emit.js / emit (unchanged) stream-json/utils/emit.js / emit

CommonJS

CJS consumers update three things together: the path (kebab-case), the binding name (camelCase, conventionally), and any .make() call sites (see .make() removed below). The default-export identity changed from class to function for most modules.

// 1.x
const StreamArray = require('stream-json/streamers/StreamArray.js');
chain([source, parser(), StreamArray.make()]);

// 2.x
const streamArray = require('stream-json/streamers/stream-array.js');
chain([source, parser(), streamArray()]);

ESM

ESM consumers see the default-export change directly, since import X from '…' of a CJS module gives you module.exports. The named-import form is the cleanest 2.x shape because the named export matches the camelCase factory:

// 1.x
import StreamArray from 'stream-json/streamers/StreamArray.js';
import parser from 'stream-json';

// 2.x
import {streamArray} from 'stream-json/streamers/stream-array.js';
import {parser} from 'stream-json';

Default-import form also works in 2.x (import streamArray from 'stream-json/streamers/stream-array.js') but you'll typically rename the binding from StreamArraystreamArray anyway, so the named-import form is less surprising.

What didn't change

These modules' runtime behavior is unchanged in 2.x — they were already functional factories in late 1.x. (Their import paths still changed per Import paths above; only the call shape stayed the same.)

Breaking changes

.make() removed

All rewritten modules no longer have .make(). Replace with the factory function or .asStream():

// 1.x
const Stringer = require('stream-json/Stringer.js');
const stream = Stringer.make(options);

// 2.x — for .pipe() usage
const stringer = require('stream-json/stringer.js');
const stream = stringer.asStream(options);

// 2.x — for chain() usage (preferred)
const stringer = require('stream-json/stringer.js');
chain([source, parser(), stringer(options)]);

new Constructor() removed

Rewritten modules are no longer classes. Using new will throw:

// 1.x
const stream = new Stringer(options);
const stream = new Emitter(options);
const stream = new Batch(options);
const stream = new Verifier(options);

// 2.x
const stream = stringer.asStream(options);
const stream = emitter(options);
const stream = batch.asStream(options);
const stream = verifier.asStream(options);

instanceof checks

If your code uses instanceof on rewritten modules, it will no longer work:

// 1.x
if (stream instanceof Stringer) { ... }

// 2.x — not possible for rewritten modules
// Use duck typing or check stream properties instead

Module-by-module migration

Stringer

Stringer is now a flushable function. Use stringer() in chain() or stringer.asStream() for .pipe().

// 1.x
const Stringer = require('stream-json/Stringer.js');
chain([source, parser(), pick({filter: 'data'}), Stringer.make()]);
// or: source.pipe(parser.asStream()).pipe(Stringer.make());

// 2.x
const stringer = require('stream-json/stringer.js');
chain([source, parser(), pick({filter: 'data'}), stringer()]);
// or: source.pipe(parser.asStream()).pipe(stringer.asStream());

All options (useValues, useKeyValues, useStringValues, useNumberValues, makeArray) work identically.

1.x 2.x
Stringer.make(options) stringer.asStream(options)
Stringer.stringer(options) stringer.asStream(options)
new Stringer(options) stringer.asStream(options)
(in chain) Stringer.make() stringer()

Emitter

Emitter is now a factory returning a Writable. Since it's a stream endpoint, both the factory and .asStream() return the same thing.

// 1.x
const Emitter = require('stream-json/Emitter.js');
const e = Emitter.make();
chain([source, parser(), e]);
e.on('startObject', () => console.log('object!'));

// 2.x
const emitter = require('stream-json/emitter.js');
const e = emitter();
chain([source, parser(), e]);
e.on('startObject', () => console.log('object!'));
1.x 2.x
Emitter.make(options) emitter(options)
Emitter.emitter(options) emitter(options)
new Emitter(options) emitter(options)

Batch

Batch is now a flushable function wrapping stream-chain/utils/batch.

// 1.x
const Batch = require('stream-json/utils/Batch.js');
chain([source, streamArray.withParser(), Batch.make({batchSize: 100})]);

// 2.x
const batch = require('stream-json/utils/batch.js');
chain([source, streamArray.withParser(), batch({batchSize: 100})]);
1.x 2.x
Batch.make(options) batch.asStream(options)
Batch.batch(options) batch.asStream(options)
new Batch(options) batch.asStream(options)
(in chain) Batch.make() batch()

The _batchSize property is still available on streams returned by batch.asStream().

Verifier

Verifier is now a gen(fixUtf8Stream(), validate) pipeline.

// 1.x
const Verifier = require('stream-json/utils/Verifier.js');
const v = Verifier.make();
v.on('error', err => console.log(err));
fs.createReadStream('data.json').pipe(v);

// 2.x
const verifier = require('stream-json/utils/verifier.js');
const v = verifier.asStream();
v.on('error', err => console.log(err));
fs.createReadStream('data.json').pipe(v);
1.x 2.x
Verifier.make(options) verifier.asStream(options)
Verifier.verifier(options) verifier.asStream(options)
new Verifier(options) verifier.asStream(options)
(in chain) Verifier.make() verifier()

Error objects still have offset, line, and pos properties.

jsonl/Parser

JsonlParser is now a gen(fixUtf8Stream(), lines(), parseLine) pipeline.

Consider using stream-chain directly. If you don't need errorIndicator or checkErrors, stream-chain/jsonl/parser is a lighter alternative that produces the same {key, value} output:

// 1.x
const JsonlParser = require('stream-json/jsonl/Parser.js');
fs.createReadStream('data.jsonl').pipe(JsonlParser.make());

// 2.x — stream-chain (recommended for simple cases)
const jsonlParser = require('stream-chain/jsonl/parserStream.js');
fs.createReadStream('data.jsonl').pipe(jsonlParser());

// 2.x — stream-json (when you need errorIndicator/checkErrors)
const jsonlParser = require('stream-json/jsonl/parser.js');
fs.createReadStream('data.jsonl').pipe(jsonlParser.asStream({errorIndicator: null}));
1.x 2.x
JsonlParser.make(options) jsonlParser.asStream(options)
JsonlParser.parser(options) jsonlParser.asStream(options)
new JsonlParser(options) jsonlParser.asStream(options)
(in chain) JsonlParser.make() jsonlParser()

stream-chain vs stream-json JSONL parser: as of stream-chain 4.2.1 these are the same parser — stream-json/jsonl/parser is a thin re-export of stream-chain/jsonl/parser, with an identical feature set (reviver, errorIndicator, ignoreErrors, checkErrors) and {key, value} output. Use stream-chain directly; stream-json's JSONL is deprecated and slated for removal in a future major.

jsonl/Stringer

JsonlStringer now delegates to stream-chain/jsonl/stringerStream. You can use stream-chain directlystream-json/jsonl/stringer.js is a thin wrapper:

// 1.x
const JsonlStringer = require('stream-json/jsonl/Stringer.js');
chain([source, JsonlParser.make(), data => data.value, JsonlStringer.make()]);

// 2.x — stream-chain (recommended)
const jsonlStringer = require('stream-chain/jsonl/stringerStream.js');
chain([source, jsonlParser(), data => data.value, jsonlStringer()]);

// 2.x — stream-json (same result, just a re-export)
const jsonlStringer = require('stream-json/jsonl/stringer.js');
chain([source, jsonlParser(), data => data.value, jsonlStringer()]);
1.x 2.x
JsonlStringer.make(options) jsonlStringer(options)
JsonlStringer.stringer(options) jsonlStringer(options)
new JsonlStringer(options) jsonlStringer(options)

The stream-chain version supports additional options: prefix, suffix, space, emptyValue.

Deprecations

Utf8Stream

Utf8Stream is deprecated. Use fixUtf8Stream from stream-chain instead:

// 1.x
const Utf8Stream = require('stream-json/utils/Utf8Stream.js');
source.pipe(new Utf8Stream());

// 2.x
const {chain} = require('stream-chain');
const fixUtf8Stream = require('stream-chain/utils/fixUtf8Stream.js');
chain([source, fixUtf8Stream()]);

The module still works but emits a DeprecationWarning once per process. It will be removed in 3.0.0.

Quick-reference cheat sheet

// 2.x imports — file names are kebab-case (was PascalCase in 1.x); see Import paths above
const stringer = require('stream-json/stringer.js');
const emitter = require('stream-json/emitter.js');
const batch = require('stream-json/utils/batch.js');
const verifier = require('stream-json/utils/verifier.js');
const jsonlParser = require('stream-json/jsonl/parser.js');
const jsonlStringer = require('stream-json/jsonl/stringer.js');

// In chain() — use the factory directly (returns a function)
chain([source, parser(), stringer()]);
chain([source, parser(), streamArray(), batch({batchSize: 100})]);
chain([source, verifier()]);
chain([source, jsonlParser()]);

// For .pipe() — use .asStream() (returns a Node stream)
source.pipe(parser.asStream()).pipe(stringer.asStream());
source.pipe(jsonlParser.asStream());
source.pipe(verifier.asStream());

// Emitter and jsonlStringer return streams directly
const e = emitter();
source.pipe(parser.asStream()).pipe(e);

Clone this wiki locally