Skip to main content
Decoders is an elegant and battle-tested validation library for type-safe input data in TypeScript. It provides runtime type checking with automatic TypeScript type inference, ensuring your data is both valid and correctly typed.

What are decoders?

TypeScript provides compile-time type safety, but it can’t validate data that arrives at runtime from external sources like APIs, user input, or configuration files. Decoders bridge this gap by:
  1. Validating data structure and types at runtime
  2. Inferring TypeScript types automatically from your validation rules
  3. Providing clear error messages when validation fails
  4. Transforming data while maintaining type safety

Why use decoders?

TypeScript can’t validate runtime data

TypeScript’s type system only exists at compile time. When data comes from external sources, TypeScript has no way to verify it matches your types:
// TypeScript trusts this is correct, but it might not be!
const apiResponse: User = await fetch('/api/user').then(r => r.json());
If the API returns unexpected data, your application may crash or behave incorrectly.

Decoders provide runtime safety

With decoders, you validate and type-check data at runtime:
import { object, string, number, array } from 'decoders';

const userDecoder = object({
  id: number,
  name: string,
  email: string,
  roles: array(string),
});

// Validate AND get type-safe result
const user = userDecoder.verify(apiResponse);
// TypeScript knows: { id: number; name: string; email: string; roles: string[] }
If validation fails, you get a clear error message explaining exactly what went wrong.

Key features

Automatic type inference

TypeScript automatically infers types from your decoder definitions - no need to write types twice

Composable

Build complex validators from simple, reusable building blocks

Zero dependencies

Tiny bundle size (~4KB) with zero runtime dependencies and full tree-shaking support

Excellent errors

Detailed error messages that pinpoint exactly what went wrong and where

Battle-tested

Used in production by thousands of projects with comprehensive test coverage

Cross-platform

Works in Node.js, browsers, Bun, Deno, and Cloudflare Workers

Basic example

Here’s a complete example showing how decoders work:
import { object, string, number, optional, array, isoDate } from 'decoders';

// Define the shape of data you expect
const userDecoder = object({
  id: number,
  name: string,
  email: optional(string),
  createdAt: optional(isoDate),
  tags: array(string),
});

// Data from an external source (API, user input, etc.)
const externalData = {
  id: 123,
  name: 'Alison Roberts',
  createdAt: '2026-01-11T12:26:37.024Z',
  tags: ['foo', 'bar'],
};

// Validate and get type-safe result
const user = userDecoder.verify(externalData);
// TypeScript infers the type:
// {
//   id: number;
//   name: string;
//   email?: string;
//   createdAt?: Date;
//   tags: string[];
// }

console.log(user.name); // 'Alison Roberts'
console.log(user.createdAt); // Date object
If the data doesn’t match the expected shape, .verify() throws an error with a detailed message.

When to use decoders

Use decoders whenever you need to validate untrusted data:
  • API responses - Validate data from external APIs
  • User input - Validate form submissions and user-provided data
  • Configuration files - Validate JSON/YAML configuration
  • Database queries - Validate data from databases
  • Message queues - Validate messages from queues like RabbitMQ or Kafka
  • Environment variables - Validate and parse environment configuration
  • File uploads - Validate uploaded file contents

How it works

Decoders use a simple three-step process:
1

Define a decoder

Create a decoder that describes the expected data structure using composable decoder functions.
2

Validate data

Call .decode() or .verify() on untrusted data to validate it against your decoder.
3

Use type-safe data

TypeScript automatically knows the validated data’s type - no manual type assertions needed.

Comparison with other libraries

FeatureDecodersZodYupio-ts
Bundle size~4KB~12KB~16KB~8KB
Dependencies00Severalfp-ts
Type inferenceLimited
Composable
Error messagesExcellentGoodGoodComplex
Learning curveLowMediumLowHigh
Decoders prioritizes simplicity, small bundle size, and excellent error messages while providing powerful composition and type inference.

Next steps

Installation

Install decoders and set up your project

Quickstart

Build your first decoder in 5 minutes

Core concepts

Understand how decoders work under the hood

API reference

Explore the complete API documentation

Build docs developers (and LLMs) love