Stop throwing, start returning.
The ZeroThrow monorepo – type-safe error handling, resilience patterns, and tooling for TypeScript.
We're currently working towards v0.3.0, which includes breaking changes to the core package and significant enhancements across the ecosystem. See ROADMAP.md for the full vision.
Affected packages in v0.3.0:
@zerothrow/core
(0.2.3 → 0.3.0) - BREAKING: ErrorCode standardization, error tracing utilities@zerothrow/resilience
(0.2.1 → 0.3.0) - Conditional retry logic, progress events, jitter support@zerothrow/react
(0.2.1 → 0.3.0) - NewuseResultForm
hook, advanced state introspection@zerothrow/jest
(1.1.1 → 1.2.0) - Enhanced matchers@zerothrow/vitest
(1.1.1 → 1.2.0) - Enhanced matchers
All feature development should target the release/v0.3.0
branch. See CONTRIBUTING.md for workflow details.
import { ZT } from '@zerothrow/core'
// ❌ This explodes somewhere in your call stack
JSON.parse(userInput)
// ✅ This returns an explicit Result<T,E>
const user = ZT.try(() => JSON.parse(userInput))
.map(validate)
.andThen(fetchFromDB)
.unwrapOr(defaultUser)
No more invisible errors. No more try/catch pyramids. Just type-safe Results.
All packages live under /packages
— each folder contains its own README, tests, and examples.
Package | Version | Description | Status |
---|---|---|---|
@zerothrow/core | Core Result<T,E> type and combinators |
🟢 Beta | |
@zerothrow/resilience | Retry, timeout, circuit breaker patterns | 🟢 Beta | |
@zerothrow/jest | Jest matchers for Result types | 🟢 Beta | |
@zerothrow/vitest | Vitest matchers for Result types | 🟢 Beta | |
@zerothrow/testing | Unified test matchers (Jest + Vitest) | 🟢 Beta | |
@zerothrow/expect | Shared test matcher logic | 🔧 Internal | |
@zerothrow/docker | Docker test utilities | 🟢 Beta | |
@zerothrow/react | React hooks and utilities for Result types | 🟢 Beta | |
@zerothrow/zt-cli | CLI tooling | 🟢 Beta |
Package | Description | Status |
---|---|---|
@zerothrow/eslint-plugin | ESLint rules to enforce no-throw |
# Core functionality
pnpm add @zerothrow/core
# Add test matchers
pnpm add --save-dev @zerothrow/jest # Jest users
pnpm add --save-dev @zerothrow/vitest # Vitest users
# Add resilience patterns (recommended for production)
pnpm add @zerothrow/resilience
import { ZT, Result } from '@zerothrow/core'
// Return Results from the start - no throwing!
async function fetchUser(id: string): Promise<Result<User, Error>> {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) {
return ZT.err(`USER_FETCH_FAILED`, `HTTP ${response.status}`)
}
// Only use try for third-party code that might throw
return ZT.try(() => response.json())
}
// Chain operations without nesting
const displayName = await fetchUser('123')
.then(r => r
.map(user => user.name.toUpperCase())
.unwrapOr('Guest')
)
console.log(`Welcome, ${displayName}!`)
- Type-safe - TypeScript knows about every possible error
- Fast - 93× faster than try/catch on error paths
- Composable - Chain operations without nesting
- Explicit - No hidden control flow
- Write functions that return Results from the beginning - Don't throw then wrap
- Only use
ZT.try
at absolute boundaries - When interfacing with code you don't control - Results are your primary return type - Not an afterthought or wrapper
Requires pnpm ≥ 9.0 (npm install -g pnpm
)
# Setup
git clone https://github.com/zerothrow/zerothrow.git
cd zerothrow
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Run specific package
pnpm --filter @zerothrow/core test
See CONTRIBUTING.md for development guidelines.
Explicit errors. No hidden control flow. Small, composable packages. Read more →
- 📖 Core Library Guide - Start here
- 🏗️ Architecture - How it all fits together
- 📦 Package Ecosystem - All packages explained
- 🔄 Migration Guide - Upgrading from v0.1.x
- 📊 Benchmarks - Performance data (
pnpm benchmark
)
- 💬 GitHub Discussions - Get help, share patterns
- 🐛 Issues - Bug reports
- 🎯 Roadmap - What's coming
MIT © 2025 ZeroThrow Contributors