https://github.com/ata-core/ata-validator
Native C++ validator built on simdjson and RE2. Hybrid JS codegen with V8 TurboFan optimizations. Up to 94x faster on $dynamicRef, 5.3x on normal schemas, 2,729x faster compilation. Full $dynamicRef/$anchor support, Draft 2020-12 + Draft 7 compatible
https://github.com/ata-core/ata-validator
fast json-schema napi native schema simdjson standard-schema validation validator
Last synced: 25 days ago
JSON representation
Native C++ validator built on simdjson and RE2. Hybrid JS codegen with V8 TurboFan optimizations. Up to 94x faster on $dynamicRef, 5.3x on normal schemas, 2,729x faster compilation. Full $dynamicRef/$anchor support, Draft 2020-12 + Draft 7 compatible
- Host: GitHub
- URL: https://github.com/ata-core/ata-validator
- Owner: ata-core
- License: mit
- Created: 2026-03-22T16:53:00.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2026-05-09T14:31:00.000Z (about 1 month ago)
- Last Synced: 2026-05-09T14:36:02.888Z (about 1 month ago)
- Topics: fast, json-schema, napi, native, schema, simdjson, standard-schema, validation, validator
- Language: JavaScript
- Homepage: https://ata-validator.com
- Size: 2.07 MB
- Stars: 328
- Watchers: 0
- Forks: 6
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# ata-validator
JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile your schemas to per-schema ESM modules with no validator dependency. `Validator` composes with TypeBox, Zod-from-JSON-Schema, Valibot, or hand-written types. Runtime API available for dynamic schemas.
[](https://www.npmjs.com/package/ata-validator)
[](LICENSE)
## Quick start
```bash
npm install --save-dev ata-validator
npx ata build 'schemas/*.json' --out-dir src/generated
```
In your code:
```ts
import { validate, isValid, type User } from './generated/user.compiled.mjs'
if (isValid(req.body)) {
const user: User = req.body
// ...
}
```
The `.compiled.mjs` modules are self-contained: zero runtime dependency on ata-validator, fully tree-shakeable, with TypeScript types emitted alongside.
## Why AOT
| Dimension | Schema | ata-AOT | AJV-runtime | Difference |
|---|---|---|---|---|
| Bundle (gzipped) | simple | 955 B | 52.7 KB | 56x smaller |
| Bundle (gzipped) | complex | 1.6 KB | 52.7 KB | 32x smaller |
| Cold start | simple | 21 ms | 38 ms | 1.8x faster |
| Throughput (10M ops) | simple | 345 Mops/s | 116 Mops/s | 3.0x faster |
| Compile time | simple | 6 µs | 1.5 ms | 246x faster |
Reproduce on your machine with `npm run bench:aot-vs-ajv`. Numbers measured on Apple M4 Pro, Node 25.2.1.
The wins are largest on bundle size and compile time because AOT moves work from runtime to build time. Throughput and cold start are also faster because the compiled validator is a tight straight-line function with no schema-walk overhead.
## When to use the runtime API instead
`ata build` is for schemas you know at build time. If your schemas are user-supplied at runtime (form builders, no-code platforms, dynamic API ingestion), use the runtime API:
```js
import { Validator } from 'ata-validator'
const v = new Validator(schema)
const result = v.validate(data)
```
The runtime API is unchanged from previous releases. AJV-shim users continue importing from `ata-validator/compat`.
## Usage
### Node.js
```javascript
const { Validator } = require('ata-validator');
const v = new Validator({
type: 'object',
properties: {
name: { type: 'string', minLength: 1 },
email: { type: 'string', format: 'email' },
age: { type: 'integer', minimum: 0 },
role: { type: 'string', default: 'user' }
},
required: ['name', 'email']
});
// Fast boolean check - JS codegen, 15.3M ops/sec
v.isValidObject({ name: 'Mert', email: 'mert@example.com', age: 26 }); // true
// Full validation with error details + defaults applied
const result = v.validate({ name: 'Mert', email: 'mert@example.com' });
// result.valid === true, data.role === 'user' (default applied)
// JSON string validation (simdjson fast path)
v.validateJSON('{"name": "Mert", "email": "mert@example.com"}');
v.isValidJSON('{"name": "Mert", "email": "mert@example.com"}'); // true
// Buffer input (zero-copy, raw NAPI)
v.isValid(Buffer.from('{"name": "Mert", "email": "mert@example.com"}'));
// Parallel batch - multi-core, NDJSON, 13.4M items/sec
const ndjson = Buffer.from(lines.join('\n'));
v.isValidParallel(ndjson); // bool[]
v.countValid(ndjson); // number
```
### Type-safe schemas
`Validator` is generic. Pair it with any schema authoring tool, or a hand-written type, to get TypeScript narrowing in your handler code.
```ts
import { Type, type Static } from '@sinclair/typebox'
import { Validator } from 'ata-validator'
const UserSchema = Type.Object({
id: Type.Integer({ minimum: 1 }),
name: Type.String({ minLength: 1 }),
email: Type.String({ format: 'email' }),
})
type User = Static
const v = new Validator(UserSchema)
if (v.isValidObject(data)) {
// data is narrowed to User, no cast needed
console.log(data.name)
}
const result = v.validate(data)
if (result.valid) {
// result.data is User
} else {
// result.errors: ValidationError[]
}
```
The same pattern works with Zod-from-JSON-Schema, Valibot, or a hand-written `type User = {...}` alongside a JSON Schema literal. `Validator` makes no library-specific assumption.
### Cross-Schema `$ref`
```javascript
const addressSchema = {
$id: 'https://example.com/address',
type: 'object',
properties: { street: { type: 'string' }, city: { type: 'string' } },
required: ['street', 'city']
};
const v = new Validator({
type: 'object',
properties: {
name: { type: 'string' },
address: { $ref: 'https://example.com/address' }
}
}, { schemas: [addressSchema] });
// Or use addSchema()
const v2 = new Validator(mainSchema);
v2.addSchema(addressSchema);
```
### Options
```javascript
const v = new Validator(schema, {
coerceTypes: true, // "42" → 42 for integer fields
removeAdditional: true, // strip properties not in schema
schemas: [otherSchema], // cross-schema $ref registry
abortEarly: true, // skip detailed error collection on failure (~4x faster on invalid data)
});
```
`abortEarly` returns a shared `{ valid: false, errors: [{ message: 'validation failed' }] }` on failure instead of running the detailed error collector. Useful when the caller only needs a pass/fail decision (Fastify route guards, high-throughput gatekeepers, request rejection at the edge).
### Build-time compile (`ata compile`)
The `ata` CLI turns a JSON Schema file into a self-contained JavaScript module. No runtime dependency on `ata-validator`, so only the generated validator ships to the browser. Typical output is ~1 KB gzipped compared to ~27 KB for the full runtime.
```bash
npx ata compile schemas/user.json -o src/generated/user.validator.mjs
```
The CLI emits two files: the validator itself and a paired `.d.mts` (or `.d.cts`) with the inferred TypeScript type plus an `isValid` type predicate.
```ts
import { isValid, validate, type User } from './user.validator.mjs'
const incoming: unknown = JSON.parse(req.body)
if (isValid(incoming)) {
// TypeScript narrows to User here
incoming.id // number
incoming.role // 'admin' | 'user' | 'guest' | undefined
}
const r = validate(incoming)
// { valid: true, errors: [] } | { valid: false, errors: ValidationError[] }
```
CLI options:
| Flag | Default | Description |
|---|---|---|
| `-o, --output ` | `.validator.mjs` | Output path |
| `-f, --format ` | `esm` | `esm` or `cjs` |
| `--name ` | from filename | Root type name in the `.d.ts` |
| `--abort-early` | off | Generate the stub-error variant (~0.5 KB gzipped) |
| `--no-types` | off | Skip the `.d.mts` / `.d.cts` output |
For a project with many schemas, `ata build ` compiles them all in one command:
```bash
npx ata build 'schemas/*.json' --out-dir build/validators --check
```
Run with `--watch` during development for incremental rebuilds.
Typical bundle sizes (10-field user schema, gzipped):
| Variant | Size | Notes |
|---|---|---|
| `ata-validator` runtime | ~27 KB | Full compiler + all keywords |
| `ata compile` (standard) | **~1.1 KB** | Validator + detailed error collector |
| `ata compile --abort-early` | **~0.5 KB** | Validator + stub errors only |
Programmatic API if you prefer to script it:
```javascript
const fs = require('fs');
const { Validator } = require('ata-validator');
const v = new Validator(schema);
fs.writeFileSync('./user.validator.mjs', v.toStandaloneModule({ format: 'esm' }));
```
**Fastify startup (10 routes cold): ajv 12.6ms → ata 0.5ms (24x faster boot, no build step required)**
### Standard Schema V1
```javascript
const v = new Validator(schema);
// Works with Fastify, tRPC, TanStack, etc.
const result = v['~standard'].validate(data);
// { value: data } on success
// { issues: [{ message, path }] } on failure
```
### Fastify Plugin
```bash
npm install fastify-ata
```
```javascript
const fastify = require('fastify')();
fastify.register(require('fastify-ata'), {
coerceTypes: true,
removeAdditional: true,
});
// All existing JSON Schema route definitions work as-is
```
### C++
```cpp
#include "ata.h"
auto schema = ata::compile(R"({
"type": "object",
"properties": { "name": {"type": "string"} },
"required": ["name"]
})");
auto result = ata::validate(schema, R"({"name": "Mert"})");
// result.valid == true
```
## Framework integrations
Copy-paste recipes for the common frameworks. Most need 10-20 lines of glue. See [docs/integrations](docs/integrations/) for the full set.
| Framework | Pattern | Recipe |
|---|---|---|
| Fastify | dedicated plugin | [`fastify-ata`](https://github.com/ata-core/fastify-ata) |
| Vite (build-time compile) | dedicated plugin | [`ata-vite`](https://github.com/ata-core/ata-vite) |
| Hono | async middleware | [docs/integrations/hono.md](docs/integrations/hono.md) |
| Elysia | direct handler check | [docs/integrations/elysia.md](docs/integrations/elysia.md) |
| tRPC | Standard Schema V1 input | [docs/integrations/trpc.md](docs/integrations/trpc.md) |
| TanStack Form | Standard Schema V1 validator | [docs/integrations/tanstack-form.md](docs/integrations/tanstack-form.md) |
| Express | sync middleware | [docs/integrations/express.md](docs/integrations/express.md) |
| Koa | async ctx middleware | [docs/integrations/koa.md](docs/integrations/koa.md) |
| NestJS | validation pipe | [docs/integrations/nestjs.md](docs/integrations/nestjs.md) |
| SvelteKit | form action, API route | [docs/integrations/sveltekit.md](docs/integrations/sveltekit.md) |
| Astro | API route, server action | [docs/integrations/astro.md](docs/integrations/astro.md) |
## Supported Keywords
| Category | Keywords |
|----------|----------|
| Type | `type` |
| Numeric | `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf` |
| String | `minLength`, `maxLength`, `pattern`, `format` |
| Array | `items`, `prefixItems`, `minItems`, `maxItems`, `uniqueItems`, `contains`, `minContains`, `maxContains`, `unevaluatedItems` |
| Object | `properties`, `required`, `additionalProperties`, `patternProperties`, `minProperties`, `maxProperties`, `propertyNames`, `dependentRequired`, `dependentSchemas`, `unevaluatedProperties` |
| Enum/Const | `enum`, `const` |
| Composition | `allOf`, `anyOf`, `oneOf`, `not` |
| Conditional | `if`, `then`, `else` |
| References | `$ref`, `$defs`, `definitions`, `$id` |
| Boolean | `true`, `false` |
### Format Validators (hand-written, no regex)
`email`, `date`, `date-time`, `time`, `uri`, `uri-reference`, `ipv4`, `ipv6`, `uuid`, `hostname`
## Building from Source
### Development prerequisites
Native builds require C/C++ toolchain support and the following libraries:
- `re2`
- `abseil`
- `mimalloc`
Install them before running `npm install` / `npm run build`:
```bash
# macOS (Homebrew)
brew install re2 abseil mimalloc
```
```bash
# Ubuntu/Debian (apt)
sudo apt-get update
sudo apt-get install -y libre2-dev libabsl-dev libmimalloc-dev
```
```bash
# C++ library + tests
cmake -B build
cmake --build build
./build/ata_tests
# Node.js addon
npm install
npm run build
npm test
# JSON Schema Test Suite
npm run test:suite
```
## License
MIT
## Authors
[Mert Can Altin](https://github.com/mertcanaltin)
[Daniel Lemire](https://github.com/lemire)