What if TypeScript had a standard library that handled errors, concurrency, retries, and observability — without 20 different npm packages?
Effect is a TypeScript library that gives you the missing pieces for building production applications.
Why Effect Exists
A typical Node.js project pulls in separate packages for error handling (neverthrow), retries (p-retry), schema validation (zod), dependency injection (tsyringe), logging (pino), and metrics (prom-client). Effect replaces all of them with one coherent system.
- Typed errors — errors are part of the type signature, not try/catch guessing
- Structured concurrency — run parallel tasks with automatic cleanup
- Built-in retries — exponential backoff, jitter, configurable policies
- Schema — runtime validation with auto-derived TypeScript types
- Dependency injection — compile-time checked, no decorators
- Observability — built-in tracing, metrics, and logging
Quick Start
npm install effect
import { Effect, Console } from "effect";
const fetchUser = (id: string) =>
Effect.tryPromise({
try: () => fetch(`/api/users/${id}`).then(r => r.json()),
catch: () => new Error("Failed to fetch user"),
});
const program = fetchUser("123").pipe(
Effect.retry({ times: 3 }),
Effect.timeout("5 seconds"),
Effect.tap((user) => Console.log(`Found: ${user.name}`)),
);
Effect.runPromise(program);
Typed Errors
class UserNotFound { readonly _tag = "UserNotFound"; }
class DatabaseError { readonly _tag = "DatabaseError"; }
const getUser = (id: string): Effect.Effect<User, UserNotFound | DatabaseError> =>
Effect.gen(function* () {
const db = yield* Database;
const user = yield* db.findById(id);
if (!user) return yield* Effect.fail(new UserNotFound());
return user;
});
const handled = getUser("123").pipe(
Effect.catchTag("UserNotFound", () => Effect.succeed(defaultUser)),
Effect.catchTag("DatabaseError", (e) => Effect.fail(new AppError(e))),
);
Real Use Case
A fintech company had 47 untyped try/catch blocks in their payment processing pipeline. Three production incidents came from swallowed errors — payments processed but confirmations silently failed. After refactoring with Effect, every error path was visible in the type system. The compiler caught 12 unhandled edge cases.
When to Use Effect
- Payment processing, financial calculations (errors matter)
- Complex async workflows with retries and timeouts
- Microservices needing structured observability
- Teams that want compile-time error checking
Get Started
Visit effect.website — comprehensive docs, Discord community, MIT licensed.
Need custom data pipelines or scraping solutions? Check out my Apify actors or email me at spinov001@gmail.com for custom solutions.
Top comments (0)