Superstruct
Library
Superstruct
Overview
Superstruct is a lightweight and flexible validation library developed as "A simple and composable way to validate data in JavaScript (and TypeScript)". Its API design, inspired by TypeScript, Flow, Go, and GraphQL, enables intuitive and simple data structure definitions. With excellent modular design and customizability, it can completely adapt to application-specific requirements. As of 2025, it is chosen by developers who prioritize lightweight and extensibility in validation libraries.
Details
Superstruct 1.0 is the latest stable version as of 2025, adopting a design philosophy that emphasizes simplicity and composability. Unlike other validation libraries, it maintains minimal core functionality and delegates all customization to users. With over 13k GitHub stars, it has gained attention as a lightweight alternative choice especially in TypeScript projects. By providing detailed error information at runtime, it is optimal for end-user applications.
Key Features
- Lightweight Design: Reduces bundle size with minimal core functionality
- Fully Customizable: Complete support for application-specific type definitions
- TypeScript Integration: Balances type inference and runtime validation
- Composable API: Builds complex schemas from simple building blocks
- Detailed Error Reporting: Detailed error information that improves debugging and user experience
- Default Value Support: Integration of data transformation and initial value setting
Pros and Cons
Pros
- Simple and intuitive API design
- Lighter and smaller bundle size compared to other libraries
- Complete customizability for application requirements
- Available for both TypeScript and JavaScript
- Easy debugging with detailed error messages
- Supports functional programming style
Cons
- Limited type inference capabilities compared to Zod
- Smaller community ecosystem
- Advanced features require additional implementation
- Relatively fewer learning resources
- Limited enterprise-level adoption cases
- Verbose descriptions needed for complex validations
Reference Pages
Code Examples
Installation and Basic Setup
# Using npm
npm install superstruct
# Using yarn
yarn add superstruct
# Using pnpm
pnpm add superstruct
Basic Data Validation
import { assert, object, number, string, array } from 'superstruct'
// Define article schema
const Article = object({
id: number(),
title: string(),
tags: array(string()),
author: object({
id: number(),
name: string(),
}),
})
// Validate data
const data = {
id: 34,
title: 'Hello World',
tags: ['news', 'features'],
author: {
id: 1,
name: 'John Doe',
},
}
try {
assert(data, Article)
console.log('Data is valid')
} catch (error) {
console.error('Validation error:', error.message)
}
Type Inference with TypeScript
import { type, object, string, number, Infer } from 'superstruct'
// Define user schema
const User = object({
name: string(),
age: number(),
email: string(),
})
// Infer TypeScript type
type UserType = Infer<typeof User>
// UserType = { name: string; age: number; email: string }
// Usage in functions
function createUser(userData: unknown): UserType {
return type(userData, User)
}
Custom Validation Implementation
import { define, string } from 'superstruct'
// Custom validator: Email address
const Email = define('Email', (value) => {
return typeof value === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
})
// Custom validator: Strong password
const StrongPassword = define('StrongPassword', (value) => {
return (
typeof value === 'string' &&
value.length >= 8 &&
/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)
)
})
// Usage example
const UserRegistration = object({
email: Email,
password: StrongPassword,
name: string(),
})
Default Values and Data Transformation
import { create, object, string, number, defaulted } from 'superstruct'
// Schema with default values
const UserProfile = object({
id: defaulted(number(), () => Math.floor(Math.random() * 1000000)),
name: string(),
role: defaulted(string(), 'user'),
createdAt: defaulted(string(), () => new Date().toISOString()),
})
// Create and transform data
const inputData = { name: 'Alice' }
const user = create(inputData, UserProfile)
console.log(user)
// {
// id: 123456,
// name: 'Alice',
// role: 'user',
// createdAt: '2025-06-22T10:30:00.000Z'
// }
Error Handling and Validation Results
import { validate, object, string, number } from 'superstruct'
const PersonSchema = object({
name: string(),
age: number(),
})
// Get validation results
const [error, result] = validate(data, PersonSchema)
if (error) {
console.error('Validation failed:', error.message)
console.error('Details:', error.failures())
} else {
console.log('Validation succeeded:', result)
}
Complex Nested Object Validation
import { object, string, number, array, optional, union } from 'superstruct'
const CompanySchema = object({
name: string(),
founded: number(),
employees: array(object({
id: number(),
name: string(),
position: string(),
salary: optional(number()),
department: union([
string(),
object({
name: string(),
budget: number(),
})
]),
})),
headquarters: object({
address: string(),
city: string(),
country: string(),
}),
})
// Validate complex data structure
const companyData = {
name: 'Tech Corp',
founded: 2020,
employees: [
{
id: 1,
name: 'Alice Johnson',
position: 'Engineer',
salary: 75000,
department: 'Engineering',
},
{
id: 2,
name: 'Bob Smith',
position: 'Manager',
department: {
name: 'Sales',
budget: 500000,
},
},
],
headquarters: {
address: '123 Tech Street',
city: 'San Francisco',
country: 'USA',
},
}
assert(companyData, CompanySchema)
Additional Notes
Superstruct is ideal for projects that prioritize lightweight and simplicity. It is an excellent choice especially when many custom validation logics are needed or when you want to minimize bundle size. It offers flexibility to leverage type inference benefits in TypeScript projects while utilizing simple APIs in JavaScript projects.