mrkeyoor.com_
Sat 08 Aug 22:52 UTC
npmDataupdated 08 Aug 2026

z-schema

z-schema is a TypeScript-based JSON Schema validator for Node.js and browsers, plus a small command-line interface. Version 12 supports draft-04, draft-06, draft-07, draft-2019-09, and draft-2020-12, which is now the default. A factory creates synchronous or asynchronous validators in throwing or result-object modes. It also compiles linked schemas, resolves registered references, supports custom formats and validation hooks, and reports structured errors with codes, paths, keywords, nested details, and schema locations.

Verdict

z-schema 12 is no longer the sleepy draft-04 validator many developers remember; it is active, typed, and current through draft-2020-12. Choose it for multi-draft coverage and rich modes, but pin the draft and budget for its Node 22 floor and major-version migration history.

API stability3/5Within v12 the factory, four validator variants, structured ValidateError details, and draft-specific options form a coherent typed API. The migration history is unusually important, though: v7 was a TypeScript and ESM rewrite, v9 replaced construction with ZSchema.create(), and v10, v11, and v12 each advanced the default JSON Schema draft. Those changes are documented and justified, but applications that omit $schema or a version option can change validation meaning across major upgrades.
Docs5/5The README gives current ESM, TypeScript, CommonJS, browser, and CLI paths, then maps all four validation modes. Separate guides cover every option, features, migration steps, architecture, testing, error fields and codes, draft comparisons, global versus instance references, async timeouts, custom formats, and schema compilation. Documentation also flags performance costs, unsafe ignore-reference behavior, global-cache collisions, format vocabulary semantics, and strictMode's exact expansion instead of hiding inconvenient details.
Maintenance5/5Version 12.4.1 was published on July 28, 2026, the repository was pushed on August 6, 2026, and the npm package uses a current TypeScript 6, Vitest 4, and modern build pipeline. It advertises 90 percent coverage and implements the JSON Schema Test Suite across five drafts. GitHub reports zero open issues and pull requests in its combined count at the captured point, while the active migration and options documentation matches the current release rather than an abandoned earlier API.
Ecosystem4/5The package recorded 3,119,555 downloads in the measured week and has 349 GitHub stars and 91 forks. It covers Node, browser UMD, ESM, CommonJS, TypeScript, and CLI consumers, and its multi-draft support helps long-lived schema estates. Ajv still has the larger mindshare, integration catalog, code-generation workflow, and third-party format ecosystem, so z-schema is a credible current choice without being the automatic default across JavaScript schema tooling.

Use it if

  • You need one validator to handle schemas spanning draft-04 through draft-2020-12
  • You want selectable throw, safe-result, async, and async-safe validation modes from the same package
  • You need structured multi-error output, custom formats, remote-reference hooks, or validation of a schema collection
  • Your runtime is Node.js 22 or newer, or you control a supported modern browser bundle
Skip it if

Setup reality

Install z-schema and use ZSchema.create(), not new ZSchema(). Version 12.4.1 requires Node.js 22 or later and publishes ESM, CommonJS, UMD, CLI, and generated TypeScript declarations. There are no native builds or credentials, but punycode, validator, and safe-regex2 are runtime dependencies; commander is optional and supports the CLI. Choose the validator mode at creation time. The default synchronous validator returns true or throws ValidateError. safe: true returns { valid, err }, async: true changes validate to a promise and is required for asynchronous format checks, and combining both produces a promise that resolves with the result object. Pick a schema version deliberately. Schemas without an explicit $schema use draft-2020-12 in v12, while older z-schema majors used different defaults; tuple items, IDs, dependencies, and format behavior can therefore change on upgrade. The default formatAssertions value keeps legacy assertion behavior, while vocabulary-aware modern-draft behavior requires an option. Pre-validate linked schemas at startup with validateSchema so bad references fail before traffic arrives. Remote schemas are not ordinary network fetches: register them on an instance or provide a carefully restricted schema reader. Global references and global custom formats cross validator-instance boundaries, which can cause test or tenant contamination. Async tasks default to a 2,000 ms timeout and are capped at 60,000 ms. Full error collection is the default; breakOnFirstError can reduce work when callers need only pass or fail. The browser UMD file exists, but server code, filesystem readers, and CLI examples do not transfer to browser deployments. strictMode bundles many opinionated checks, so enable individual options if you do not want its entire schema policy.

Patterns

Validate without exceptionsvalidate-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 modecatch-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 migrationpin-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 safelyvalidate-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 startupcompile-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 validatorregister-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 readerrestrict-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 formatregister-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 payloadsstop-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 segmentsreport-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 branchvalidate-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 CLIvalidate-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
ajvnpmYou want the dominant high-performance JSON Schema compiler, standalone code generation, and a broad plugin ecosystem
@hyperjump/json-schemanpmYou prioritize modern JSON Schema dialect architecture and spec-focused evaluation APIs
jsonschemanpmYou need a familiar older validation API and your schemas fit its supported drafts
djvnpmYou have a constrained hot path and want a compact dynamic validator for a narrower feature set