English | Русский
Runtime contracts for TypeScript: define one schema, validate unknown input at runtime, infer static types, and generate tooling artifacts from the same source.
TypeScript types disappear at runtime. SafeShape keeps the runtime boundary explicit: no hidden coercion, immutable schemas, stable diagnostics, and strong type inference from the contract you actually execute.
Use SafeShape when data crosses a trust boundary:
- API requests and responses.
- JSON files and config.
- CLI input and generated artifacts.
- Webhook payloads and integration events.
- Any
unknownvalue that must become typed data.
Zod is the broader validation ecosystem today. SafeShape is intentionally narrower: it treats runtime schemas as public contracts that must stay explicit, documented, toolable, and release-tested.
| Decision | Zod | SafeShape |
|---|---|---|
| Primary goal | TypeScript-first schema validation | Runtime contract platform |
| API shape | Broad convenience surface | Conservative stable surface |
| Coercion | Rich convenience APIs, including coercion-oriented workflows | No hidden coercion; transforms are explicit |
| Tooling | Large ecosystem and built-in conversion features | First-party CLI, JSON Schema export, TypeScript generation, validation reports |
| HTTP boundaries | Usually handled through adapters or app code | First-party framework-neutral HTTP helpers |
| Contract evolution | Application-specific tooling | Deterministic input/output graph snapshots, fingerprints, recursion, and conservative compatibility reports |
| Ecosystem protocol | Standard Schema support | Native Standard Schema V1 with explicit async support, warning extension, side-aware Standard JSON Schema adapters, and richer immutable diagnostics |
| Tagged composition | Discriminated union validation | Selected-branch diagnostics plus first-party Contract IR, snapshots, JSON Schema, and TypeScript artifacts |
| Failed unions | invalid_union issues retain branch errors |
Ordered recursive branch diagnostics are preserved consistently through native errors, validation reports, CLI, HTTP, and Standard Schema |
| Cross-field rules | Checks and refinement hooks can add issues | Stable-id sync/async rules emit ordered errors or warnings with structured parameters across every first-party boundary |
| Toolable constraints | Broad validation surface | Exact decimal multipleOf, constrained record keys, and explicit object policies retain one meaning across runtime, Contract IR, compatibility, JSON Schema, and CLI |
| Release posture | Mature general-purpose library | Contract-first release gate with tests, examples, benchmarks, consumer install, audit, and pack dry-run |
The comparison reflects the current Zod 4 API, JSON Schema support, and ecosystem documentation.
Choose Zod when you need the largest ecosystem and the widest validation feature set. Choose SafeShape when you want a smaller contract layer with explicit runtime behavior, stable diagnostics, first-party tooling, and package boundaries that are designed for API stability.
Install the full runtime and tooling surface:
npm install safe-shapeDefine a schema and validate unknown input:
import { integer, object, string, type Infer } from "safe-shape";
const User = object({
id: string({ minLength: 1, maxLength: 100 }),
age: integer({ minimum: 0, maximum: 150 }).optional(),
});
type User = Infer<typeof User>;
const result = User.safeParse({ id: "user_1", age: 42 });
if (!result.success) {
console.error(result.error.issues);
} else {
const user: User = result.data;
console.log(user.id);
}SafeShape validates without coercion. { age: "42" } is invalid until you add an
explicit transform.
SafeShape 3.0 supports non-fatal diagnostics and explicit async rules:
const Name = string().warnAsync(async (value) => value.length >= 3, {
id: "name.short/v1",
message: "Name is unusually short.",
params: { recommendedMinimum: 3 },
});
const result = await Name.safeParseAsync("x");
// result.success === true; result.warnings contains the warningSynchronous entry points stay synchronous and reject schemas containing async rules before parsing. See Migrating from 2.x to 3.0.
SafeShape also ships a CLI. Use it to turn runtime contracts into generated artifacts:
safe-shape --json schema export \
--module ./dist/contracts/user.js \
--export User \
--schema https://json-schema.org/draft/2020-12/schema \
--out ./dist/contracts/user.schema.jsonsafe-shape --json schema types \
--module ./dist/contracts/user.js \
--export User \
--name User \
--out ./dist/contracts/user.d.tsStore a reviewable contract baseline and block incompatible changes in CI:
safe-shape contract snapshot \
--module ./dist/contracts/user.js \
--export User \
--id user \
--format v2 \
--out ./.safe-shape/user.contract.json
safe-shape --json contract check \
--module ./dist/contracts/user.js \
--export User \
--against ./.safe-shape/user.contract.json \
--side input \
--compatibility backwardThe CLI is machine-readable under --json, treats validation failures as
command results, includes migration decisions in compatibility reports, and
does not require authentication. Snapshot v1 remains the default; v2 is
explicit for recursive and input/output graph contracts.
Use groupIssuesByPath() to retain native structural paths and original issue
objects, or toFieldErrors() to create an immutable form-oriented error
record. Per-call formatters let applications localize issue messages without
putting locale state on schemas or in global process state. Ordinary union
branches remain explicit and are never flattened implicitly.
Use recoverHttpResponse() at deployed HTTP boundaries to validate a network
value and an eager or lazy fallback through the same response contract. It
returns a frozen valid, recovered, or unavailable state and never treats
either invalid payload as inferred response data.
SafeShape keeps reporting, storage, retry, and UI policy in application code; it never weakens the production schema. See the Production Response Recovery guide for the typed flow, telemetry guidance, CI compatibility check, and a runnable example.
Current stable release gate:
| Signal | Status |
|---|---|
| Packages | 8 publishable packages |
| Unit tests | 220 passing tests |
| Consumer install | Tarball install smoke check passes |
| Examples | Runnable examples pass |
| Security audit | 0 known vulnerabilities |
| Benchmarks | 22 runtime, diagnostics, projection, and compatibility scenarios |
| Package dry run | npm pack --workspaces --dry-run passes |
Sample local benchmark run on Node.js v20.10.0 / macOS arm64:
| Scenario | Throughput |
|---|---|
Primitive string safeParse valid |
6,719,546 ops/sec |
Passing warning rule safeParse valid |
5,386,557 ops/sec |
Emitted structured warning safeParse valid |
1,441,738 ops/sec |
Formatted email string safeParse valid |
4,026,028 ops/sec |
Decimal multipleOf safeParse valid |
2,247,231 ops/sec |
Constrained record safeParse valid |
1,014,617 ops/sec |
Strip object safeParse valid |
961,256 ops/sec |
Passthrough object safeParse valid |
642,620 ops/sec |
Object user safeParse valid |
155,301 ops/sec |
Standard Schema user validate valid |
142,706 ops/sec |
Union event safeParse valid |
31,041 ops/sec |
Union event safeParse invalid with branch diagnostics |
13,405 ops/sec |
Discriminated union event safeParse valid |
437,840 ops/sec |
Intersection string safeParse valid |
2,435,011 ops/sec |
Array users safeParse valid |
7,627 ops/sec |
Object user safeParse invalid |
58,959 ops/sec |
| Group 200 issues by path | 36,316 ops/sec |
| Project 200 issues to field errors | 9,830 ops/sec |
Recursive tree safeParse valid |
289,690 ops/sec |
| Contract compatibility widening safe | 40,492 ops/sec |
| Contract compatibility narrowing breaking | 40,501 ops/sec |
| Recursive contract v2 compatibility widening safe | 11,190 ops/sec |
Benchmark results are execution evidence, not fixed release thresholds. Re-run them locally with:
npm run build
npm run benchmarks:checkInstall safe-shape when you want the complete public surface from one package.
Import only what each module needs:
import { object, string, validateSchema } from "safe-shape";Use narrower packages when you want strict dependency boundaries:
| Package | Purpose |
|---|---|
safe-shape |
Umbrella package that re-exports runtime and tooling APIs |
@safe-shape/core |
Runtime schemas, parsing, diagnostics, and type inference |
@safe-shape/compat |
Deterministic snapshots and compatibility analysis |
@safe-shape/http |
Framework-neutral HTTP boundary helpers |
@safe-shape/json-schema |
JSON Schema export |
@safe-shape/typescript |
TypeScript declaration generation |
@safe-shape/validation |
JSON-friendly validation reports |
@safe-shape/cli |
Command-line tooling |
- Runtime first.
- API stability over feature count.
- Immutable schemas and parse results.
- Rich diagnostics with stable issue paths.
- Correctness before performance.
- Performance before convenience.
- No magic and no hidden coercion.
- Documentation home
- Quick start
- Migrating from 1.x to 2.0
- Migrating from 2.x to 3.0
- Project integration
- Core API
- Contract compatibility
- CLI API
- HTTP helpers
- Production Response Recovery
- JSON Schema export
- TypeScript generation
- Validation reports
- Benchmarks
- Release workflow
- Contract checks in CI
- Документация на русском
npm install
npm run build
npm run test
npm run docs:check
npm run release:checkUse the built CLI without a global install:
npm run cli:doctorRunnable examples live in examples:
npm run examples:checkSafeShape is on the 3.0.0 stable release line. The release gate covers
metadata checks, build, typecheck, tests, examples, benchmarks, consumer tarball
installation, npm audit, and package dry-run.
