DEV Community

Diego Teles
Diego Teles

Posted on

Porting Zod to C#: ZodSharp – A Zero-Allocation, High-Performance Schema Validation Library for .NET

Porting Zod to C#: ZodSharp – A Zero-Allocation, High-Performance Schema Validation Library for .NET

As a .NET developer, I’ve long been frustrated by one persistent pain point: most validation libraries rely heavily on reflection, leading to slow performance and constant allocations. Whether it’s validating API inputs, forms, or data pipelines, that overhead adds up — especially in high-throughput scenarios.

Then I discovered Zod — the gold standard for schema validation in the TypeScript world, created by colinhacks. Its fluent API, full type inference, excellent error messages, and zero-dependency design made it feel like magic. But there was nothing quite like it in C#.

So I decided to change that. I built ZodSharp — a complete, from-scratch rewrite of Zod tailored for modern .NET, with a relentless focus on performance, zero-allocation, and developer experience.

This post is the story of that journey and why ZodSharp might just become your new go-to validation library.


Why Zod Became the Standard in TypeScript

Zod dominates the JS/TS ecosystem for good reason:

  • Fluent, chainable API that's a joy to write
  • Full type safety with automatic inference
  • Powerful composition for complex schemas
  • Rich transforms and refinements
  • Clear, structured error reporting
  • Zero runtime dependencies

In .NET, we have solid options like FluentValidation, but they lean on reflection and expressions — great for flexibility, but costly in performance-critical paths.

ZodSharp brings that same elegant developer experience to C# — without the allocation tax.


Not a Simple Port — A Performance-First Rewrite

While staying faithful to Zod’s public API and semantics, nearly every internal detail was re-engineered for .NET’s strengths.

Zero-Allocation: The Core Design Goal

The #1 priority: validation should produce zero garbage in hot paths.

Reflection-based validation creates objects, closures, and temporary collections on every call. ZodSharp eliminates that entirely.

Key techniques:

  1. Validation rules as structs
   public readonly struct MinLengthRule : IValidationRule<string>
   {
       private readonly int _min;
       public MinLengthRule(int min) => _min = min;

       public bool IsValid(in string value) => value.Length >= _min;
   }
Enter fullscreen mode Exit fullscreen mode
  1. Immutable collections with minimal overhead (ImmutableArray, ImmutableDictionary)

  2. ValidationResult as a struct — no heap allocation on success or failure

  3. ArrayPool for any temporary buffers

  4. Manual loops instead of LINQ in performance-critical sections

  5. Span and ReadOnlySpan for string operations with zero copies


Fluent API — As Close to Zod as Possible

The API feels instantly familiar to Zod users:

// Almost identical to Zod TS
var schema = Z.String()
    .Min(3)
    .Max(50)
    .Email()
    .Trim()
    .ToLower();
Enter fullscreen mode Exit fullscreen mode

Object schemas:

var userSchema = Z.Object()
    .Field("name", Z.String().Min(1))
    .Field("age", Z.Number().Min(0).Max(120))
    .Field("email", Z.String().Email())
    .Build();
Enter fullscreen mode Exit fullscreen mode

Transforms, refinements, unions, optionals, literals — all supported.


Source Generators & DataAnnotations Integration

One of the biggest .NET-specific wins: compile-time schema generation.

Decorate a class with [ZodSchema] and use standard DataAnnotations — ZodSharp generates a static schema at build time:

[ZodSchema]
public class User
{
    [Required, StringLength(50, MinimumLength = 3)]
    public string Name { get; set; } = string.Empty;

    [Range(0, 120)]
    public int Age { get; set; }

    [EmailAddress]
    public string Email { get; set; } = string.Empty;
}

// Usage
var result = UserSchema.Validate(new User { ... });
Enter fullscreen mode Exit fullscreen mode

No runtime reflection needed.


Project Architecture Overview

ZodSharp/
├── src/ZodSharp/
│   ├── Core/                → Interfaces, base classes, results, errors
│   ├── Schemas/             → String, Number, Object, Array, Union, etc.
│   ├── Rules/               → Struct-based validation rules
│   ├── Expressions/         → Compiled validators via Expression Trees
│   ├── Json/                → Newtonsoft.Json integration
│   ├── Optimizations/       → Zero-allocation helpers
│   └── Z.cs                 → Static factory (Z.String(), Z.Object(), etc.)
├── src/ZodSharp.SourceGenerators/
│   └── ZodSchemaGenerator.cs → [ZodSchema] source generator
├── example/                 → Full usage samples
└── README.md
Enter fullscreen mode Exit fullscreen mode

Rough Performance Wins

Early benchmarks show dramatic improvements over typical reflection-based validation:

Scenario Reflection-Based ZodSharp Gain
Simple string validation ~0.15 ms ~0.01 ms ~15× faster
Complex object validation ~0.8 ms ~0.05 ms ~16× faster
Allocations per validation Multiple Zero Eliminated

The gap widens under load.


Practical Use Cases

ZodSharp shines anywhere validation performance matters:

  • High-throughput APIs (REST, gRPC, GraphQL)
  • Microservices with frequent input validation
  • Real-time systems
  • Data ingestion pipelines
  • Desktop/mobile apps with complex forms
  • Anywhere you want Zod-like DX without the runtime cost

What’s Already Implemented

  • Fluent schema building
  • Full primitive support (string, number, boolean, array, object, union, literal)
  • Transforms (.Trim(), .ToLower(), etc.)
  • Refinements (custom validation)
  • Optional / nullable wrappers
  • Discriminated unions
  • Lazy/recursive schemas
  • Source generator with DataAnnotations
  • Newtonsoft.Json integration
  • Advanced string rules (.Url(), .Uuid(), .Email(), .StartsWith()...)
  • Advanced number rules (.Positive(), .MultipleOf(), .Finite()...)

What’s Next?

  • Public benchmark suite
  • ASP.NET Core model binding integration
  • Entity Framework validation hooks
  • More JSON serializer support (System.Text.Json)
  • Enhanced error formatting
  • Community contributions!

Final Thoughts

Building ZodSharp was incredibly rewarding. It wasn’t just about bringing Zod to C# — it was about solving a real, widespread pain in the .NET ecosystem: fast, type-safe, zero-overhead validation.

If you’ve ever groaned at reflection slowdowns or wished for a more modern validation experience in C#, I hope you’ll give ZodSharp a try.

GitHub: https://github.com/guinhx/ZodSharp

NuGet: https://www.nuget.org/packages/ZodSharp

Original Zod: https://github.com/colinhacks/zod

Feedback, stars, issues, and PRs are very welcome! Let me know — have you felt the reflection validation pain? What would make you switch?

Thanks for reading! 🚀

Tags: #dotnet #csharp #validation #zod #performance #opensource #typesafety

Top comments (0)