TypeScript → JSON IR → Rust
Write the schema once. It compiles to JSON, then validates identically in JavaScript, TypeScript, and Rust: same transforms, same rules, same error codes. One source of truth, no drift across runtimes.
$npm i wellformed-ts
MIT · TS & Rust · 60+ validators
Where the rules travel
Your form isn't always a web page.
Often the form isn't fixed in your code. It's built in a form builder, configured per customer, or one of hundreds of forms that each carry their own rules. And whatever renders or receives it, the browser, the backend, a Rust service, needs those same rules.
Most validation libraries write those rules as code, and code is not data. You can't store a closure in a database, load the rules for one customer's form, or hand them to a Rust service. So every form gets hardcoded and every rule rewritten by hand, and the copies drift out of sync.
wellformed compiles the rules to JSON. Store them with each form, load them at runtime, and run them unchanged in TypeScript and Rust.
How it works
Author once. Compile to data. Run anywhere.
Write the schema with a Zod-like builder. wellformed compiles it to a JSON IR: a complete program of predicates, transforms, error codes, and cross-field rules, with nothing hidden in closures.
Store that IR, send it over the wire, or load it by id. The TypeScript and Rust runtimes read the same file and validate identically.
w.object({ … }).when(…).require(…)author · ts
account.schema.jsonportable ir
Batteries included
Everything you'd otherwise re-implement on both sides.
Performance
Purpose-built beats regex.
Most validators lean on generic regex. wellformed's built-in predicates are purpose-built, so an email or SSN checks in tens of nanoseconds instead of microseconds. That is 10 to 40x faster than Zod in the same V8 runtime, and the Rust runtime goes further with SIMD-friendly byte scanners.
wellformed-tsZod
Validation latency, lower is faster. Same V8 runtime, Apple Silicon.
Stop maintaining two copies of the truth.
Define your validation once. Ship it as data. Run it everywhere.
$npm i wellformed-ts