DEV Community

Alex Spinov
Alex Spinov

Posted on

Effect-TS Has a Free API — TypeScript Standard Library for Production Apps

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
Enter fullscreen mode Exit fullscreen mode
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);
Enter fullscreen mode Exit fullscreen mode

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))),
);
Enter fullscreen mode Exit fullscreen mode

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)