Skip to main content

Superstruct vs Zod: Lightweight vs Feature-Rich (2026)

·PkgPulse Team
0

TL;DR

Zod for most projects; Superstruct when bundle size is critical. Superstruct (~2M weekly downloads) is ~7KB gzipped and has a simple functional API. Zod (~20M downloads) is ~28KB but has richer built-in validators, better ecosystem integration, and more active development. For most web apps, Zod's size difference is negligible. For edge functions or browser bundles where every KB matters, Superstruct is worth evaluating.

Key Takeaways

  • Zod: ~20M weekly downloads — Superstruct: ~2M (npm, March 2026)
  • Superstruct: ~7KB gzipped — Zod: ~28KB gzipped
  • Superstruct uses plain functions — no method chaining (different style)
  • Zod has better TypeScript inference — Superstruct types require manual casting
  • Zod is much more actively maintained — more contributors, faster releases

The Validation Library Landscape

TypeScript validation libraries solve the boundary problem: at system boundaries (HTTP request bodies, environment variables, user inputs), you receive untyped data that TypeScript can't verify at compile time. Validation libraries give you runtime type checking that produces TypeScript types from the validation schema.

The ecosystem has several strong options in 2026:

  • Zod — the dominant choice, full-featured, 20M downloads
  • Superstruct — minimal and functional, 2M downloads
  • Valibot — tree-shakeable, similar to Superstruct's philosophy but newer
  • ArkType — TypeScript-native syntax, cutting-edge type inference
  • Yup — legacy, still widely used especially with Formik

Superstruct and Valibot occupy a similar niche: smaller bundle size, functional composition style, suitable for bundle-size-constrained environments. Zod occupies the full-featured niche: richer validators, extensive integrations, dominant ecosystem position.


API Style

// Zod — method chains, OOP-ish API
import { z } from 'zod';

const User = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().positive(),
  tags: z.array(z.string()).optional(),
});

const result = User.safeParse(data);
if (result.success) {
  const user = result.data; // Typed as { name: string; email: string; ... }
}
// Superstruct — functional API, plain composable functions
import { object, string, number, array, optional, min, max, integer, positive } from 'superstruct';

const User = object({
  name: string(),   // min/max need to be added separately (custom types)
  email: string(),  // No built-in .email() — add custom refinement
  age: integer(),   // positive() refinement
  tags: optional(array(string())),
});

const [error, value] = User.try(data);
// value is Infer<typeof User> = { name: string; email: string; ... }

The style difference is fundamental. Zod's method-chaining API (z.string().email().min(3)) reads left-to-right and maps naturally to "a string that is an email with a minimum of 3 characters." Superstruct's functional composition style (min(string(), 3)) is more composable but requires more function calls for complex validation.

For developers coming from Yup or other method-chaining validation libraries, Zod's style feels familiar. For developers who prefer functional programming patterns, Superstruct's approach is more consistent.


Bundle Size

Library       | Minified+Gzip | Note
--------------|---------------|------
Superstruct   | ~7KB          | Minimal, tree-shakeable
Valibot       | ~8KB          | Functional, tree-shakeable
ArkType       | ~10KB         | TypeScript-native syntax
Zod v4        | ~28KB         | Full-featured
Joi           | ~45KB         | JavaScript-first, largest

For comparison: React is ~40KB gzipped

The 21KB difference between Superstruct and Zod matters in specific contexts:

Edge functions: Cloudflare Workers have a 1MB script size limit. Bundling Zod (~28KB) versus Superstruct (~7KB) saves 21KB of compressed bundle size — meaningful when every KB affects cold start time and you're close to limits.

Library authors: If you're publishing an npm package that others install, pulling in Zod adds 28KB to every consumer's bundle. A smaller dependency like Superstruct imposes less overhead on users.

Browser-only apps on slow connections: For apps targeting users in bandwidth-constrained environments, every KB matters.

For typical SaaS web apps served from CDN, the 21KB difference is negligible in a >500KB total bundle. Don't prematurely optimize.


Custom Types

// Superstruct — custom types via refinement
import { refine, string } from 'superstruct';

const Email = refine(string(), 'Email', (value) => {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
    || `Expected an email but got "${value}"`;
});

const PositiveNumber = refine(number(), 'PositiveNumber', (value) => {
  return value > 0 || `Expected a positive number but got ${value}`;
});
// Zod — built-in types for common validations
z.string().email()       // Built in
z.string().url()         // Built in
z.string().uuid()        // Built in
z.number().positive()    // Built in
z.number().int()         // Built in

// Custom refinement when needed:
z.string().refine(
  (val) => isValidUsername(val),
  { message: 'Invalid username format' }
);

Superstruct's functional refine() is actually quite clean for custom types. The pattern of "take a base type and add a validation function" is explicit and testable. The downside is that you have to write common validators (email, URL, UUID) yourself, while Zod provides them as built-in methods.


Transformation

// Superstruct — coerce utility
import { create, string, number } from 'superstruct';
const coerced = create('42', number()); // Throws if can't coerce

// Or use coerce() for default transformations:
import { coerce, defaulted } from 'superstruct';
const NumberFromString = coerce(number(), string(), (value) => parseFloat(value));
// Zod — transform built into schemas
const FormData = z.object({
  age: z.string().transform(Number),    // String → Number
  date: z.string().transform(s => new Date(s)),  // String → Date
  name: z.string().trim().toLowerCase(), // Chain transforms
});

Zod's transform() is more ergonomic: you define the transformation in the same schema definition that validates the type. This is particularly useful for HTTP form inputs where everything comes as strings but you want typed output.

Superstruct's coerce() is functional and explicit but requires more verbosity for similar transformations.


Ecosystem Integrations

Zod's dominant ecosystem position means it has first-class integrations across the JavaScript ecosystem:

  • React Hook Form: @hookform/resolvers/zod — official Zod resolver
  • tRPC: uses Zod schemas for input validation natively
  • Drizzle ORM: Zod schema inference from database tables
  • Next.js Server Actions: type-safe server action input validation
  • OpenAI SDK: structured output validation
  • Fastify: fastify-type-provider-zod

Superstruct has fewer official integrations. For React Hook Form, there is a @hookform/resolvers/superstruct resolver, but it's less documented and maintained than the Zod version.

If you're building with tRPC or Drizzle, Zod is essentially required — both libraries are designed around Zod as the validation layer. Switching to Superstruct would mean losing those integrations.


When to Choose

Choose Zod when:

  • Standard web application development
  • Using React Hook Form, tRPC, or Drizzle (native integrations)
  • Bundle size isn't a constraint (>100KB total bundle)
  • Richer built-in validators save development time
  • Team productivity over raw bundle optimization

Choose Superstruct when:

  • Library author who doesn't want to impose large dependency on users
  • Edge function bundle size is critical (<100KB total budget)
  • Functional composition style is preferred
  • You need a lightweight validation baseline with custom extensions
  • Publishing an npm package others will install

The reality: for 95% of web development, Zod is the better choice. Superstruct's advantage is real but situational. Also consider Valibot as a modern alternative to Superstruct — it has a similar bundle footprint but a more active development community in 2026.


Compare Superstruct and Zod package health on PkgPulse. Also see our Joi vs Zod comparison and best form libraries for React for validation in context.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.