mrkeyoor.com_
Wed 23 Sept 03:42 UTC
npmDataupdated 22 Sept 2026

z-schema review

z-schema 12.4.3 validates JSON values against draft-04, draft-06, draft-07, draft-2019-09, or draft-2020-12 schemas in Node.js and browsers. `ZSchema.create()` selects synchronous or asynchronous validation and either thrown errors or result objects; compiled references, custom formats, schema readers, and structured error details cover larger schema sets. Version 12 defaults schemas without `$schema` to draft-2020-12 and requires Node 22. Our install found an ESM package with an exports map, but no TypeScript declarations despite TypeScript examples in the README.

Verdict

Our z-schema 12.4.3 install took 1.2 seconds, occupied 4 MB across 8 packages, bundled to 30.7 KB gzipped, and had 0 audit findings, but it shipped no TypeScript declarations on our box. Use it for multi-draft validation modes on Node 22; choose Ajv when generated speed, plugins, or stronger TS tooling matter more.

We installed it

Lab card: what happened when we installed z-schemaScreenshot of z-schema documentation
Install✓ · 1.2s8 packages on disk · 4 MB
ImportESM import works · require() works · ESM package with exports map
Browser30.7 KBgzipped (117.9 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does z-schema install cleanly?

Yes. In a fresh container with an empty cache, npm install z-schema finished in 1 seconds, leaving 8 packages and 4 MB on disk. npm audit reported no known vulnerabilities.

How much does z-schema add to a browser bundle?

30.7 KB gzipped (117.9 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does z-schema work with both ESM and CommonJS?

Yes. Both import 'z-schema' and require('z-schema') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does z-schema include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

z-schema or ajv: which should you use?

ajv: Use it for generated validators, high throughput, and a large formats and keywords ecosystem. Our z-schema 12.4.3 install took 1.2 seconds, occupied 4 MB across 8 packages, bundled to 30.7 KB gzipped, and had 0 audit findings, but it shipped no TypeScript declarations on our box.

When should you not use z-schema?

Node 20 or older is still supported by the application; 12.4.3 declares Node 22 minimum.

API stability2/5The current factory cleanly defines four validator modes, but recent majors changed core expectations: v9 replaced construction with `ZSchema.create()`, and v10, v11, and v12 each moved the default draft. A schema with an explicit `$schema` is insulated from part of that churn. Global registration APIs and package-specific strict options still enlarge the compatibility surface.
Docs4/5The README covers Node 22, ESM and CommonJS loading, browser UMD use, CLI commands, all four safe and async modes, compilation, custom formats, remote references, version history, and links to options, features, migration, architecture, and testing guides. Its TypeScript examples conflict with our installed 12.4.3 package, where no declaration files were found, so that claim needs correction.
Maintenance5/5npm published 12.4.3 on 2026-08-20, and GitHub reports a push on the same date with 0 open issues and pull requests at fetch time. The repository is not archived and documents the 2020-12 and 2019-09 work plus earlier drafts. This is strong current activity, though the quick succession of major default changes raises upgrade cost even when maintenance is healthy.
Ecosystem3/5npm recorded 3,135,340 downloads for the week ending 2026-08-24. The package spans five JSON Schema drafts, Node, browser UMD, CLI, references, custom formats, and four validation modes. Ajv still has the larger plugin and code-generation ecosystem, and z-schema's 30.7 KB gzipped measured browser cost plus missing installed declarations reduce its appeal for typed frontend applications.

Use it if

  • One validator must handle draft-04 through draft-2020-12 with an explicit version choice.
  • Callers need either thrown structured errors or safe `{ valid, err }` results, synchronously or asynchronously.
  • Linked schemas will be compiled at startup and remote references are registered under application policy.
  • Custom synchronous or asynchronous format checks are part of the schema contract.
Skip it if

Setup reality

Our z-schema 12.4.3 install completed in 1.2 seconds and left 8 packages using 4 MB on disk. The package is 1,460 KB unpacked, has 3 direct dependencies and 0 peers, and returned 0 known vulnerabilities from npm audit. Its engine requirement is Node 22 or newer, with no native compilation or credentials.

Version 12.4.3 is an ESM package with an exports map. Both require() and ESM import worked on Node 22. We found no TypeScript declaration files in the installed package, so the README's TypeScript examples do not provide first-party compile-time types on our box. Check that gap before adopting it in a strict TS project.

Create validators with ZSchema.create(). Default validation returns true or throws ValidateError; safe: true returns a result object, async: true returns a promise, and both options combine. Schemas lacking $schema use draft-2020-12 in v12, so pin the draft in long-lived schemas instead of inheriting a future major's default.

Precompile linked schemas with validateSchema at startup. Register remote references yourself or install a restricted schema reader; never turn schema URIs into unrestricted filesystem or network access. Global readers, references, and custom formats can affect separate instances. Async tasks default to a 2,000 ms timeout and cap at 60,000 ms. Our browser bundle measured 117.9 KB minified and 30.7 KB gzipped, which is expensive for a client form if a smaller validator covers its draft.

Patterns

Validate without exceptions validate-with-safe-result

import ZSchema from 'z-schema';

const validator = ZSchema.create({ safe: true });
const result = validator.validate(data, schema);
if (!result.valid) {
  console.error(result.err?.details);
}

safe is a factory option that changes validate's return type. A default validator instead returns true or throws ValidateError.

Handle structured errors in throw mode catch-validation-error

const validator = ZSchema.create();
try {
  validator.validate(data, schema);
} catch (error) {
  if (error.name === 'ValidateError') {
    for (const detail of error.details) {
      console.error(detail.path, detail.keyword, detail.message);
    }
  } else {
    throw error;
  }
}

Do not parse the summary message. details provides stable codes, keyword names, data paths, schema paths, and nested errors.

Pin draft-07 behavior during migration pin-schema-draft

const validator = ZSchema.create({ version: 'draft-07' });

validator.validate(data, {
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
});

Version 12 defaults schemas without an explicit declaration to draft-2020-12. Pinning both configuration and $schema makes intent reviewable.

Run an asynchronous format check safely validate-async-format

const validator = ZSchema.create({
  async: true,
  safe: true,
  asyncTimeout: 1500,
});
validator.registerFormat('user-exists', async (id) => {
  return typeof id === 'number' && await users.exists(id);
});

const result = await validator.validate(data, schema);

Async format functions require async: true. The timeout applies to async work and is silently capped at 60,000 ms.

Compile schemas with cross-references at startup compile-linked-schemas

const schemas = [
  { $id: 'person', type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
  { $id: 'team', type: 'object', properties: { lead: { $ref: 'person' } } },
];

const validator = ZSchema.create();
validator.validateSchema(schemas);
validator.validate({ lead: { name: 'Ada' } }, schemas[1]);

Compile before serving requests so invalid schemas and unresolved links fail during startup rather than on the first matching payload.

Register a remote reference on one validator register-instance-reference

const validator = ZSchema.create();
validator.setRemoteReference(
  'https://schemas.example/address.json',
  addressSchema
);
validator.validate(data, rootSchema);

Instance references take precedence and avoid the process-wide last-write-wins cache used by ZSchema.setRemoteReference.

Load references through an allowlisted reader restrict-schema-reader

ZSchema.setSchemaReader((uri) => {
  const schema = approvedSchemas.get(uri);
  if (!schema) throw new Error(`Schema URI not allowed: ${uri}`);
  return schema;
});

The package does not safely download arbitrary remote schemas for you. Do not map untrusted URIs directly to filesystem paths or unrestricted HTTP requests.

Add an instance-scoped format register-custom-format

const validator = ZSchema.create();
validator.registerFormat('order-id', (value) => {
  return typeof value === 'string' && /^ORD-[0-9]{8}$/.test(value);
});

validator.validate('ORD-00123456', { type: 'string', format: 'order-id' });

Prefer instance registration when tests or tenants use different rules. Global ZSchema.registerFormat affects every instance in the process.

Short-circuit invalid production payloads stop-at-first-error

const validator = ZSchema.create({
  safe: true,
  breakOnFirstError: true,
});
const { valid, err } = validator.validate(request.body, schema);

The default collects all errors. Short-circuit only when the caller does not need a complete list for a form or diagnostics.

Return machine-friendly path segments report-array-paths

const validator = ZSchema.create({
  safe: true,
  reportPathAsArray: true,
});
const result = validator.validate(data, schema);
const path = result.err?.details[0]?.path;
// for example: ['users', 0, 'email']

Without reportPathAsArray, paths use JSON Pointer-like strings such as #/users/0/email. Choose one representation at your API boundary.

Validate against one schema branch validate-subschema

validator.validate(address, rootSchema, {
  schemaPath: '#/properties/address',
});

schemaPath targets a schema location, not a path into the data. Validate the corresponding data value yourself.

Check a schema and payload from the CLI validate-from-cli

npx z-schema schema.json data.json
npx z-schema --strictMode schema.json data.json

strictMode enables a bundle of opinionated schema checks, including required maxLength, properties, items, and additional-property declarations. It is not merely stricter value validation.

Alternatives

PackageRegistryPick it when
ajvnpmUse it for generated validators, high throughput, and a large formats and keywords ecosystem.
@exodus/schemasafenpmUse it for security-focused JSON Schema compilation with a smaller option surface.
jsonschemanpmUse it for a simpler validator API when modern-draft breadth and code generation are not priorities.

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.