Introduction
A small, typed architecture for Result-based TypeScript applications.
Build applications around explicit dependencies
Most application code has two independent questions:
- Did this operation succeed?
- What does this operation need in order to run?
better-result answers the first
question with a typed Result. better-effect answers the second without
introducing a second error model, a fiber runtime, or a dependency container
that your application has to learn.
Effect.gen / fn describe a Result workflow and its Service requirements
Layer describes how Services are provided
Runtime owns the environment and executes workflows
Scope owns resources and finalizers
better-result remains the source of truth for success and failureThe complete path
define a Service
↓
write an Effect.fn Program (or an eager Effect.gen workflow)
↓
provide implementations with Layer
↓
execute through Runtime
↓
release resources through ScopeThe library is intentionally small. It gives you a composition root and lifetime boundaries while leaving HTTP, queues, scheduling, persistence and dependency injection to ordinary TypeScript libraries or adapters. Browse the package catalog for the complete set of published packages. For the Layer-first HTTP client with buffered responses, NDJSON, SSE, and opt-in Hono streaming, see HTTP client. For provider-neutral validation, see Schema. For Better Auth, Kysely and MQ integrations, see Better Auth, Kysely integration, and the MQ guide.
All integration APIs in the current release are Layer-first. If you are upgrading an older application, start with the migration guide before copying an example from an older version.
Layers expose a simple Layer<Provided, Required> contract. Provided and
Required are tagged Service instance unions; after composition, Required
contains only dependencies that remain external.
Choose your starting point
Start with Getting Started, then read the Mental Model. You will build one Service, provide it through a Layer, and run it with a Runtime.
What this library is not
better-effect is not a reimplementation of Effect. It does not add fibers,
schedulers, streams, queues, a full Context abstraction, or a lazy instruction
tree. Its public Effect<A, E, R> is a type-only facade over a better-result
Result (or Promise of one), with R carrying declaration-only tagged Service instance
requirements.
That smaller boundary is a feature: use the pieces when they solve a concrete problem and keep the rest of your application conventional.