Fortify Schema

The Future of TypeScript Validation
What if schema validation looked exactly like TypeScript interfaces? Fortify Schema brings tomorrow's validation patterns to today's TypeScript developers. We're not competing with existing libraries - we're showing what validation will look like in 2025.
Interface-native syntax. Revolutionary conditional validation. Perfect TypeScript integration.
Documentation Navigation
The Evolution of TypeScript Validation
2020-2023: Method Chaining Era
z.object({
name: z.string().min(2).max(50),
role: z.enum(["admin", "user"]),
permissions: z.array(z.string()).optional(),
});
2024+: Interface Era (Fortify Schema)
Interface({
name: "string(2,50)",
role: "admin|user",
permissions: "when role=admin *? string[] : string[]?",
});
The difference? 70% less code, perfect TypeScript alignment, and conditional validation that actually works.
Fortify Schema isn't just another validation library - it's the evolution of how we think about data validation in TypeScript. We bring interface-native syntax to runtime validation, making schemas that look and feel exactly like TypeScript interfaces while providing revolutionary conditional validation capabilities.
Key Features
Advanced Conditional Validation
- 20+ operators for comparison, pattern matching, and logical operations
- TypeScript inference - IDE understands conditional types
- Nested conditions - Multi-level conditional logic support
- Business rule modeling - Express complex domain logic naturally
Developer Experience
- Interface-like syntax familiar to TypeScript developers
- Type inference reduces manual type definitions
- Compile-time validation catches errors early
- Rich IDE support with autocomplete and error detection
Performance & Reliability
- Optimized validation - Efficient parsing and evaluation
- Caching system - Reuses parsed expressions
- Memory efficient - Minimal runtime overhead
- Comprehensive testing - Extensive test suite coverage
Early Access to the Future
Current Status: Revolutionary Beta
Fortify Schema represents the next generation of TypeScript validation. While established libraries serve today's needs, we're building tomorrow's validation patterns.
Perfect for Forward-Thinking Teams:
- Innovation projects: Teams exploring cutting-edge TypeScript patterns
- Greenfield applications: New projects that can benefit from modern validation approaches
- Complex business logic: Applications requiring sophisticated conditional validation
- TypeScript enthusiasts: Developers who want validation that feels native to TypeScript
When to Consider Established Libraries:
- Legacy system integration: When extensive ecosystem compatibility is required
- Risk-averse environments: Teams preferring battle-tested solutions
- Simple validation needs: Basic schemas without conditional logic
The Trade-off: Choose between today's proven patterns or tomorrow's revolutionary approach. Early adopters of jQuery (2005), React (2013), and TypeScript (2017) gained significant competitive advantages. Fortify Schema offers the same opportunity for validation.
Library Comparison Overview
See why developers are migrating to Fortify Schema from traditional validation libraries:
Code Comparison
Zod | Fortify Schema | 70% Less Code |
z.number().int().positive() | "positive" | 24 → 10 chars |
z.string().min(2).max(50) | "string(2,50)" | 25 → 15 chars |
z.array(z.string()).min(1).max(10) | "string[](1,10)" | 33 → 17 chars |
z.enum(["active", "inactive"]) | "active|inactive" | 31 → 17 chars |
z.string().optional() | "string?" | 21 → 9 chars |
Real-World Schema Comparison
Traditional Approach (Zod):
import { z } from "zod";
const UserSchema = z.object({
id: z.number().int().positive(),
email: z.string().email(),
name: z.string().min(2).max(50),
age: z.number().int().min(18).max(120).optional(),
tags: z.array(z.string()).min(1).max(10).optional(),
status: z.enum(["active", "inactive", "pending"]),
role: z.literal("admin"),
});
Fortify Schema Approach:
import { Interface } from "fortify-schema";
const UserSchema = Interface({
id: "positive",
email: "email",
name: "string(2,50)",
age: "int(18,120)?",
tags: "string[](1,10)?",
status: "active|inactive|pending",
role: "admin|user",
});
Result: 50% fewer characters, zero learning curve, perfect type inference
Conditional Validation
Problem with Existing Libraries:
const schema = z
.object({
role: z.enum(["admin", "user"]),
permissions: z.array(z.string()).optional(),
})
.refine(
(data) => {
if (data.role === "admin" && !data.permissions) {
return false;
}
return true;
},
{ message: "Admin users must have permissions" }
);
Fortify Schema Solution:
const EnterpriseUserSchema = Interface({
id: "uuid",
email: "email",
role: "admin|manager|employee|contractor|guest",
department: "engineering|sales|marketing|hr|finance",
accountType: "enterprise|professional|standard|trial",
systemPermissions: "when role.in(admin,manager) *? string[] : string[]?",
departmentAccess:
"when role=manager *? string[] : when role=admin *? string[] : =[]",
maxProjects:
"when accountType=trial *? =3 : when accountType=standard *? =10 : when accountType=professional *? =50 : =unlimited",
apiAccess: "when accountType.in(professional,enterprise) *? boolean : =false",
customIntegrations: "when accountType=enterprise *? boolean : =false",
mfaRequired:
"when role.in(admin,manager) *? =true : when accountType=enterprise *? =true : boolean",
profile: {
firstName: "string(1,50)",
lastName: "string(1,50)",
teamSize: "when role.in(manager,admin) *? int(1,) : int?",
directReports: "when role.in(manager,admin) *? string[] : string[]?",
},
});
const result = EnterpriseUserSchema.safeParse(userData);
if (result.success) {
}
Complete Migration Guide - Detailed comparisons and migration strategies
Why Developers Choose Fortify Schema
Dramatic Simplification
- Up to 70% reduction in schema definition code
- TypeScript interface-like syntax developers already know
- Single import for most validation scenarios
Superior Type Safety
- Exact literal types instead of generic unions
- Perfect IDE integration with autocomplete and error detection
Enterprise Performance
- Optimized validation algorithms
- Tree-shakable architecture for minimal bundle impact
- Zero runtime type overhead
The Fortify Schema Solution
Clean, Intuitive Syntax
import { Interface } from "fortify-schema";
const UserSchema = Interface({
id: "number",
email: "email",
name: "string(2,50)",
age: "number(18,120)?",
tags: "string[](1,10)?",
status: "active|inactive",
role: "=admin",
});
Advanced Type Inference
const result = UserSchema.safeParse(userData);
if (result.success && result.data) {
result.data.status;
result.data.role;
result.data.age;
}
UserSchema.safeParse({
id: 1,
name: "John",
invalidProp: "error",
});
Conditional Validation with Perfect Type Inference
The world's first schema library with conditional validation that provides complete TypeScript inference support
const UserSchema = Interface({
role: "admin|user|guest",
accountType: "free|premium|enterprise",
permissions: "when role=admin *? string[] : string[]?",
maxProjects: "when accountType=free *? int(1,3) : int(1,)",
paymentMethod: "when accountType!=free *? string : string?",
billingAddress: "when paymentMethod.exists *? string : string?",
});
const adminUser = {
role: "=admin" as const,
permissions: ["read", "write", "delete"],
maxProjects: 100,
paymentMethod: "credit_card",
};
const regularUser = {
role: "=user" as const,
accountType: "free" as const,
maxProjects: 2,
};
const invalidUser = {
role: "=user" as const,
permissions: ["read", 2],
};
Three Approaches Available:
- Advanced Conditional Syntax (Crystal clear + Perfect TypeScript inference)
- Parentheses Syntax (Clear structure, runtime only)
- Import-based Syntax (Fluent API, most powerful)
import { When } from 'fortify-schema';
permissions: "when role=admin *? string[] : string[]?",
permissions: "when(role=admin) then(string[]) else(string[]?)",
permissions: When.field("role").is("admin").then("string[]").else("string[]?")
Why the conditional syntax is powerful:
- Crystal clear boundaries: Easy to see where condition ends and logic begins
- Perfect TypeScript inference: Full compile-time type checking
- No conflicts: Doesn't interfere with optional
?
operator
- Intuitive: Reads like natural language
- Professional: Clean and elegant syntax
Note: The parentheses syntax works perfectly at runtime but has limited TypeScript inference due to nested parentheses in template literal types. Use the *?
syntax for the best developer experience.
Installation
npm install fortify-schema
Requirements:
- TypeScript 4.5+
- Node.js 14+
Quick Start Guide
Basic Schema Definition
import { Interface } from "fortify-schema";
const UserSchema = Interface({
id: "number",
email: "email",
name: "string",
age: "number?",
isActive: "boolean?",
tags: "string[]?",
status: "active|inactive|pending",
role: "=user",
});
Schema Transformation
import { Mod } from "fortify-schema";
const PublicUserSchema = Mod.omit(UserSchema, ["password"]);
const PartialUserSchema = Mod.partial(UserSchema);
const ExtendedSchema = Mod.extend(UserSchema, {
createdAt: "date",
lastLogin: "date?",
});
Data Validation
const result = UserSchema.safeParse(userData);
if (result.success) {
console.log("✅ Valid user:", result.data);
} else {
console.log("❌ Validation errors:", result.errors);
}
const unknownResult = UserSchema.safeParseUnknown(apiResponse);
Core Concepts
Field Types
Complete Field Types Reference - Comprehensive guide to all available types and constraints
Basic Types
{
name: "string",
age: "number",
active: "boolean",
created: "date",
data: "any"
}
Optional Fields
{
name: "string",
age: "number?",
bio: "string?",
tags: "string[]?"
}
Format Validation
{
email: "email",
website: "url",
id: "uuid",
phone: "phone",
slug: "slug",
username: "username"
}
Array Types
{
tags: "string[]",
scores: "number[]",
flags: "boolean[]",
emails: "email[]"
}
Advanced Type Definitions
Constants and Unions
import { Make } from 'fortify-schema';
{
version: Make.const("1.0"),
status: Make.const(200),
priority: Make.union("low", "medium", "high"),
role: Make.unionOptional("user", "admin", "moderator")
}
Why use Make
? It eliminates ambiguity between type specifications and constant values, making schemas more readable and maintainable.
Conditional Validation
Fortify Schema provides the first conditional validation system with complete TypeScript inference:
Advanced Conditional Syntax (Recommended)
{
role: "admin|user|guest",
permissions: "when role=admin *? string[] : string[]?",
maxProjects: "when accountType=free *? int(1,3) : int(1,)",
paymentMethod: "when accountType!=free *? string : string?",
billingAddress: "when paymentMethod.exists *? string : string?",
seniorDiscount: "when age>=65 *? number : number?",
adminFeatures: "when role.in(admin,moderator) *? string[] : string[]?"
}
Parentheses Syntax (Also Clear)
{
role: "admin|user|guest",
permissions: "when(role=admin) then(string[]) else(string[]?)",
maxProjects: "when(accountType=free) then(int(1,3)) else(int(1,))",
paymentMethod: "when(accountType!=free) then(string) else(string?)"
}
Import-based Conditional Validation (Most Powerful)
import { When } from 'fortify-schema';
{
role: "admin|user|guest",
permissions: When.field("role").is("admin").then("string[]").else("string[]?"),
maxProjects: When.field("accountType").is("free").then("int(1,3)").else("int(1,)"),
paymentMethod: When.field("accountType").isNot("free").then("string").else("string?")
}
Conditional Syntax Reference
Advanced Conditional Syntax | | |
"when condition *? then : else" | Crystal clear syntax | "when role=admin *? string[] : string[]?" |
"when condition *? then" | Only when condition | "when role=admin *? string[]" |
Parentheses Syntax | | |
"when(condition) then(schema) else(schema)" | Explicit structure | "when(role=admin) then(string[]) else(string[]?)" |
Legacy Syntax (Still supported but not recommended) | | |
"when:field=value:then:else" | Legacy format | "when:role=admin:string[]:string[]?" |
Condition Operators:
Comparison Operators:
=
- Equality: "when role=admin *? ..."
!=
- Not equal: "when status!=pending *? ..."
>
, >=
- Greater than: "when age>=18 *? ..."
<
, <=
- Less than: "when score<50 *? ..."
Pattern Operators:
~
- Regex match: "when email~^admin *? ..."
!~
- Negative regex: "when email!~@temp *? ..."
Existence Operators:
.exists
- Field exists: "when email.exists *? ..."
.!exists
- Field does not exist: "when email.!exists *? ..."
State Operators:
.empty
- Field is empty: "when description.empty *? ..."
.!empty
- Field is not empty: "when tags.!empty *? ..."
.null
- Field is null: "when optional.null *? ..."
.!null
- Field is not null: "when required.!null *? ..."
Array Operators:
.in(a,b,c)
- Value in array: "when role.in(admin,mod) *? ..."
.!in(a,b,c)
- Value not in array: "when role.!in(guest) *? ..."
String Operators:
.startsWith(value)
- String starts with: "when filename.startsWith(temp_) *? ..."
.endsWith(value)
- String ends with: "when filename.endsWith(.tmp) *? ..."
.contains(value)
- String contains: "when path.contains(/secure/) *? ..."
.!contains(value)
- String does not contain: "when path.!contains(/temp/) *? ..."
Benefits of the *?
syntax:
- No confusion with optional
?
operator
- Crystal clear where condition ends and logic begins
- Natural language flow that's easy to read
Complete TypeScript Integration:
- ✅ Compile-time type checking for conditional fields
- ✅ Exact type inference based on conditions
- ✅ IDE autocomplete and error detection
- ✅ Runtime validation with full data context
Constraint System
String Constraints
{
username: "string(3,20)",
password: "string(8,)",
bio: "string(,500)?",
title: "string(10,100)",
}
Number Constraints
{
age: "number(18,120)",
score: "number(0,100)",
price: "number(0.01,999.99)",
rating: "number(1,5)?",
}
Array Constraints
{
tags: "string[](1,10)?",
scores: "number[](3,5)",
items: "any[](1,)",
emails: "email[](,20)",
}
Pattern Validation
{
slug: "string(/^[a-z0-9-]+$/)",
phone: "string(/^\\+?[1-9]\\d{1,14}$/)",
code: "string(/^[A-Z]{2,4}$/)",
hexColor: "string(/^#[0-9a-fA-F]{6}$/)",
}
Constraint Reference Table
"string(min,max)" | Length constraints | "string(3,20)" |
"string(min,)" | Minimum length only | "string(8,)" |
"string(,max)" | Maximum length only | "string(,100)" |
"string(/regex/)" | Pattern validation | "string(/^[a-z]+$/)" |
"number(min,max)" | Value range | "number(0,100)" |
"type[](min,max)" | Array size constraints | "string[](1,10)" |
"type?" | Optional field | "string?" |
Schema Transformation with Mod
The Mod
utility provides powerful schema transformation capabilities:
Combining Schemas
const UserSchema = Interface({ id: "number", name: "string" });
const ProfileSchema = Interface({ bio: "string?", avatar: "url?" });
const CompleteSchema = Mod.merge(UserSchema, ProfileSchema);
Selecting Fields
const UserSchema = Interface({
id: "number",
name: "string",
email: "email",
password: "string",
createdAt: "date",
});
const PublicSchema = Mod.pick(UserSchema, ["id", "name", "email"]);
const SafeSchema = Mod.omit(UserSchema, ["password"]);
Modifying Field Requirements
const PartialSchema = Mod.partial(UserSchema);
const RequiredSchema = Mod.required(OptionalSchema);
const ExtendedSchema = Mod.extend(UserSchema, {
lastLogin: "date?",
isVerified: "boolean",
});
Complex Transformations
const APIResponseSchema = Mod.extend(
Mod.omit(Mod.merge(UserSchema, ProfileSchema), ["password", "internalId"]),
{
metadata: {
version: Make.const("2.0"),
timestamp: "date",
},
}
);
Validation Modes
Strict Mode (Default)
Fortify Schema is strict by default, respecting exactly what you specify:
const schema = Interface({
id: "number",
name: "string",
});
const result = schema.safeParse({
id: "1",
name: "John",
});
Loose Mode (Type Coercion)
Enable automatic type conversion when needed:
const looseSchema = Interface({
id: "number",
active: "boolean",
}).loose();
const result = looseSchema.safeParse({
id: "123",
active: "true",
});
console.log(result.success);
console.log(result.data);
console.log(result.warnings);
Strict Object Mode
Prevent additional properties:
const strictSchema = Interface({
id: "number",
name: "string",
}).strict();
const result = strictSchema.safeParse({
id: 1,
name: "John",
age: 25,
});
Validation Methods
Parse Methods
try {
const user = UserSchema.parse(userData);
} catch (error) {
console.error("Validation failed:", error.message);
}
const result = UserSchema.safeParse(userData);
if (result.success) {
console.log("Valid data:", result.data);
} else {
console.log("Errors:", result.errors);
}
const unknownResult = UserSchema.safeParseUnknown(apiResponse);
Result Structure
{
success: true,
data: T,
errors: [],
warnings: string[]
}
{
success: false,
data: null,
errors: string[],
warnings: string[]
}
Real-World Examples
User Management System
const UserSchema = Interface({
id: "uuid",
email: "email",
username: "string(3,20)",
password: "string(8,)",
role: Make.union("user", "moderator", "admin"),
status: Make.union("active", "inactive", "suspended"),
profile: {
firstName: "string(1,50)",
lastName: "string(1,50)",
avatar: "url?",
bio: "string(,500)?",
dateOfBirth: "date?",
},
age: "number(13,120)?",
tags: "string[](1,10)?",
permissions: "string[](,20)?",
createdAt: "date",
lastLogin: "date?",
accountType: Make.const("standard"),
preferences: {
theme: Make.union("light", "dark", "auto"),
notifications: "boolean",
language: "string(/^[a-z]{2}$/)",
},
});
API Response Schema
const APIResponseSchema = Interface({
version: Make.const("2.0"),
timestamp: "date",
requestId: "uuid",
status: Make.union("success", "error", "partial"),
statusCode: "number(100,599)",
data: "any?",
errors: "string[]?",
warnings: "string[]?",
pagination: {
page: "number(1,)",
limit: "number(1,100)",
total: "number(0,)",
hasMore: "boolean"
}?,
meta: {
environment: Make.union("development", "staging", "production"),
region: "string(/^[a-z]{2}-[a-z]+-\\d$/)",
cached: "boolean?",
ttl: "number(0,)?"
}
});
E-commerce Product Schema
const ProductSchema = Interface({
id: "uuid",
sku: "string(/^[A-Z0-9-]{6,20}$/)",
name: "string(1,200)",
slug: "string(/^[a-z0-9-]+$/)",
category: "string",
subcategory: "string?",
tags: "string[](,20)",
price: "number(0.01,99999.99)",
originalPrice: "number(0.01,99999.99)?",
currency: "string(/^[A-Z]{3}$/)",
stock: "number(0,)",
stockStatus: Make.union("in-stock", "low-stock", "out-of-stock"),
description: "string(,5000)",
shortDescription: "string(,500)?",
specifications: "any?",
images: "url[](1,10)",
videos: "url[](,3)?",
status: Make.union("draft", "active", "archived"),
featured: "boolean",
createdAt: "date",
updatedAt: "date",
seo: {
title: "string(,60)?",
description: "string(,160)?",
keywords: "string[](,10)?"
}?
});
Performance and Bundle Size
Optimization Features
- Tree-shakable: Only import what you use
- Minimal runtime: Optimized validation algorithms
- Type inference: Zero runtime type overhead
- Efficient parsing: Fast validation with detailed error messages
Bundle Impact
import { Interface } from "fortify-schema";
import { Interface, Make } from "fortify-schema";
import { Interface, Make, Mod } from "fortify-schema";
import {
Smart,
When,
Live,
Docs,
Extensions,
Quick,
TypeScriptGenerator,
} from "fortify-schema";
import { Smart } from "fortify-schema";
import { When } from "fortify-schema";
import { Live } from "fortify-schema";
import { Docs } from "fortify-schema";
Migration Guide
From Zod
const zodSchema = z.object({
name: z.string().min(2).max(50),
age: z.number().int().positive().optional(),
email: z.string().email(),
role: z.enum(["user", "admin"]),
});
const fortifySchema = Interface({
name: "string(2,50)",
age: "number(1,)?",
email: "email",
role: Make.union("user", "admin"),
});
From Joi
const joiSchema = Joi.object({
name: Joi.string().min(2).max(50).required(),
age: Joi.number().integer().positive(),
email: Joi.string().email(),
});
const fortifySchema = Interface({
name: "string(2,50)",
age: "number(1,)",
email: "email",
});
TypeScript Integration
Perfect Type Inference
Fortify Schema provides industry-leading TypeScript integration:
const schema = Interface({
id: "number",
name: "string",
tags: "string[]?",
status: Make.union("active", "inactive"),
role: Make.const("user"),
});
type InferredType = typeof schema._type;
Compile-Time Safety
const result = schema.safeParse({
id: 1,
name: "John",
invalidProperty: "error",
});
const unknownResult = schema.safeParseUnknown(apiData);
IDE Support
- IntelliSense: Full autocomplete for schema properties
- Type checking: Real-time validation of schema definitions
- Error highlighting: Immediate feedback on type mismatches
- Hover information: Detailed type information on hover
API Reference
Interface()
Create a schema from an interface-like definition.
Interface(definition: SchemaDefinition): Schema<T>
Make
Utility for creating complex types safely.
Make.const(value);
Make.union(...values);
Make.unionOptional(...values);
Mod
Schema transformation utilities.
Mod.merge(schema1, schema2);
Mod.pick(schema, keys);
Mod.omit(schema, keys);
Mod.partial(schema);
Mod.required(schema);
Mod.extend(schema, definition);
Extensions
Advanced features for complex validation scenarios.
Smart.fromSample(data);
Smart.fromJsonSchema(jsonSchema);
Smart.fromType<T>();
When.field("role").is("admin").then("string[]").else("string[]?");
When.custom((data) => data.age >= 18)
.then("string")
.else("string?");
Live.validator(schema);
Live.stream(schema);
Docs.generate(schema);
Docs.typescript(schema);
Docs.openapi(schema);
Extensions.Smart.fromSample(data);
Extensions.When.field("role");
Extensions.Live.validator(schema);
Quick.fromSample(data);
Quick.when("role").is("admin");
Quick.live(schema);
Quick.docs(schema);
Schema Methods
schema.parse(data);
schema.safeParse(data);
schema.safeParseUnknown(data);
schema.loose();
schema.strict();
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
git clone https://github.com/Nehonix-Team/fortify-schema.git
npm install
npm test
npm run build
Reporting Issues
Please use our GitHub Issues to report bugs or request features.
License
MIT © Nehonix Team
Support and Community
Built with precision and care by the Nehonix Team