@exodus/schemasafe review
@exodus/schemasafe 1.3.0 compiles JSON Schema into JavaScript functions that either validate an existing value or parse and validate a raw JSON string in one step. The compiler rejects schema keywords it cannot account for, can require every object and array path to be checked, and can emit a self-contained module for environments where runtime code generation is blocked. It covers drafts 04, 06, 07, 2019-09, and 2020-12 plus a limited OpenAPI discriminator. Our install found a 172 KB CommonJS package with bundled TypeScript declarations, no direct or peer dependencies, and working require() and ESM import. Version 1.3.0 added explicit spec mode and formatAssertion controls for newer draft behavior.
@exodus/schemasafe 1.3.0 installed in 1 second as one 1 MB package with 0 audit findings in our sandbox, and parser mode can keep unvalidated JSON objects out of application code. Install it for strict, buildable JSON Schema checks; choose Ajv for a larger ecosystem or Zod when inferred TypeScript types own the contract.
We installed it
| Install | ✓ · 1s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 19.4 KB | gzipped (55.4 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does @exodus/schemasafe install cleanly?
Yes. In a fresh container with an empty cache, npm install @exodus/schemasafe finished in 1 seconds, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does @exodus/schemasafe add to a browser bundle?
19.4 KB gzipped (55.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does @exodus/schemasafe work with both ESM and CommonJS?
Yes. Both import '@exodus/schemasafe' and require('@exodus/schemasafe') worked in Node 22 in our run. The package is published as CommonJS.
Does @exodus/schemasafe include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
@exodus/schemasafe or ajv: which should you use?
ajv: Use it when plugin breadth, standalone generation, ecosystem integrations, and mature TypeScript helpers outweigh schemasafe's smaller surface. @exodus/schemasafe 1.3.0 installed in 1 second as one 1 MB package with 0 audit findings in our sandbox, and parser mode can keep unvalidated JSON objects out of application code.
When should you not use @exodus/schemasafe?
Your team relies on a broad plugin and tooling market around JSON Schema. Ajv has a larger extension ecosystem and more current TypeScript integration.
Use it if
- A service accepts raw JSON and should expose the parsed value only after both syntax and schema checks succeed.
- Schema compilation must reject unknown, unused, unreachable, or nonsensical keywords instead of quietly ignoring them.
- A build can generate self-contained validator modules for a strict Content Security Policy or a reviewable deployment artifact.
- JSON Schema is the interchange contract, and drafts 04 through 2020-12 cover the schemas your systems already publish.
- Your team relies on a broad plugin and tooling market around JSON Schema. Ajv has a larger extension ecosystem and more current TypeScript integration.
- Precise TypeScript inference from a schema is part of the requirement. The bundled declaration labels itself experimental and known to be incomplete.
- Schemas contain private extension keywords that the validator does not process. Default and strong modes reject leftovers; strong mode also forbids allowUnusedKeywords.
- Neither runtime function generation nor a build-time generation step is permitted. The normal compiler creates JavaScript, while CSP deployments need toModule() output prepared ahead of time.
- An actively released validator is required for policy or support reasons. Version 1.3.0 dates to August 2023, and the repository last pushed in May 2025.
Setup reality
Our clean Node 22 sandbox installed @exodus/schemasafe 1.3.0 in 1 second. One package used 1 MB on disk; its published unpacked size is 172 KB. npm audit reported 0 known vulnerabilities across every severity. The package declares 0 direct and 0 peer dependencies, bundles TypeScript declarations, and uses CommonJS without an exports map. Both require() and ESM import worked in our checks.
No credentials, native build, or config file is needed. The first decision is API shape. validator() receives a JavaScript value and returns a Boolean. parser() receives JSON text and returns an object with valid and, on success, value. Parser mode enables strong checks by default, including a required $schema declaration, validation coverage for every property or item path, string constraints, and basic complexity guards.
Compilation errors throw synchronously, while bad input returns false or a failed parser result. Error details cost an explicit includeErrors option; allErrors has an effect only when includeErrors is also true. useDefaults and removeAdditional can mutate the value produced by validation, and compilation refuses schemas where that mutation would be ambiguous. Treat schemas as trusted configuration because the security notes still allow denial-of-service risk from hostile schemas.
Runtime compilation creates functions. Under a strict CSP, call toModule() during a trusted build and ship the generated module. Our browser bundle measurement was 55.4 KB minified and 19.4 KB gzipped, so client use has a visible cost even though the package installs alone. Version 1.3.0 keeps format checks enabled by default; mode: 'spec' or formatAssertion: false opts into the annotation behavior of drafts 2019-09 and 2020-12.
Patterns
Compile a Boolean validator validate-object
const { validator } = require('@exodus/schemasafe')
const validateUser = validator({
type: 'object',
required: ['name'],
properties: { name: { type: 'string', minLength: 1 } },
additionalProperties: false,
})
if (!validateUser(input)) throw new Error('invalid user')validator() accepts an already parsed value and returns true or false. Schema mistakes throw when the validator is compiled.
Accept only validated JSON text parse-and-validate
const { parser } = require('@exodus/schemasafe')
const parseUser = parser({
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
required: ['name'],
properties: { name: { type: 'string', minLength: 1 } },
additionalProperties: false,
})
const result = parseUser(body)
if (!result.valid) return { status: 400 }
useUser(result.value)parser() enables strong mode by default. result.value is undefined when JSON parsing or schema validation fails.
Report every available validation error collect-errors
const validate = validator(schema, {
includeErrors: true,
allErrors: true,
})
if (!validate(payload)) {
console.error(validate.errors)
}allErrors requires includeErrors. Each reported item carries keywordLocation and instanceLocation JSON pointers.
Apply strong checks to object validation enable-strong-mode
const validate = validator(schema, { mode: 'strong' })Strong mode requires $schema, full property and item coverage, string validation, and complexity checks. It rejects allowUnusedKeywords and allowUnreachable.
Register an application format add-custom-format
const validate = validator(
{ type: 'string', format: 'order-id' },
{ formats: { 'order-id': /^ord_[0-9a-f]{16}$/ } },
)
assert(validate('ord_0123456789abcdef'))Custom formats accept a RegExp or function. They are trusted code when a validator module is generated.
Supply a referenced schema resolve-external-ref
const address = {
$id: 'address',
type: 'object',
required: ['city'],
properties: { city: { type: 'string' } },
}
const validate = validator(
{ $ref: 'address#' },
{ schemas: [address] },
)The schemas option accepts an array, Map, or object. Array entries need a top-level $id for reference resolution.
Emit a validator during the build generate-module
const { writeFileSync } = require('node:fs')
const { validator } = require('@exodus/schemasafe')
const validate = validator(schema)
writeFileSync('generated/validate-user.js', `module.exports = ${validate.toModule()}\n`)toModule() returns self-contained JavaScript. Generate it in a trusted build when runtime code creation is blocked by CSP.
Insert declared default values apply-defaults
const validate = validator({
type: 'object',
properties: { limit: { type: 'integer', default: 20 } },
additionalProperties: false,
}, { useDefaults: true })
const query = {}
validate(query)
assert.equal(query.limit, 20)useDefaults mutates the validated object. Compilation fails when schema branching makes default insertion ambiguous.
Strip fields forbidden by the schema remove-extra-properties
const parse = parser({
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
properties: { id: { type: 'integer' } },
additionalProperties: false,
}, { removeAdditional: true, mode: 'default' })
const result = parse('{"id": 7, "debug": true}')
assert.deepEqual(result.value, { id: 7 })removeAdditional changes the parsed result. Review that data loss explicitly instead of treating it as ordinary validation.
Disable format assertion for a current draft use-spec-format-behavior
const validate = validator(schema2020, { mode: 'spec' })Version 1.3.0 added spec mode. For draft 2019-09 and newer, it treats format as annotation unless formatAssertion is set back to true.
Collect schema construction errors lint-schema
const { lint } = require('@exodus/schemasafe')
for (const issue of lint(schema, { mode: 'strong' })) {
console.error(issue.keywordLocation, issue.message)
}lint() is experimental. Its exact messages and details may change without a major version bump.
Check a schema without producing code dry-run-schema
validator(schema, {
dryRun: true,
mode: 'strong',
})dryRun validates schema coherence and throws on the first error without returning a validator function.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| ajv | npm | Use it when plugin breadth, standalone generation, ecosystem integrations, and mature TypeScript helpers outweigh schemasafe's smaller surface. |
| jsonschema | npm | Use it when direct runtime validation is preferable to generated functions and your draft requirements fit its implementation. |
| zod | npm | Use it when application developers author schemas in TypeScript and inferred static types matter more than portable JSON Schema documents. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · 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.

