Effect is a TypeScript library for building production-grade software with typed errors, structured concurrency, dependency injection, and built-in observability.
Before writing Effect code, detect which version the user is on:
bash
# Check installed version
cat package.json | grep '"effect"'
Context.Service, Effect.catch, Effect.forkChild, Schema.TaggedErrorClassContext.Tag, Effect.catchAll, Effect.fork, Data.TaggedErrorNote: v4 beta briefly used a
ServiceMapmodule, renamed back toContexton 2026-04-07 (PR #1961). If you seeServiceMap.*in any doc or older beta code, it is the currentContext.*. Both v3 and v4 importContextfrom"effect"; the exports inside differ (Context.Servicein v4 vsContext.Tagin v3).
Prefer v4 for new projects - it's where Effect is going. In an existing codebase, match the installed version: don't rewrite v3 code in v4 syntax unless asked. If the version is genuinely unclear, default to v4 and say so. v4 is still in beta, so pin an exact version ( 4.0.0-beta.x) and expect occasional API churn.
v4 (primary):
v3 (for existing codebases):
Both versions:
LLM outputs frequently contain incorrect Effect APIs. Verify every API against the reference docs before using it.
Common hallucinations (both versions):
Wrong (AI often generates)CorrectEffect.cachedWithTTL(...)``Cache.make({ capacity, timeToLive, lookup })``Effect.cachedInvalidateWithTTL(...)``cache.invalidate(key) / cache.invalidateAll()``Effect.mapError(effect, fn)``Effect.mapError(fn) in pipe, or use Effect.catchTag``import { Schema } from "@effect/schema"``import { Schema } from "effect" (v3.10+ and all v4)import { JSONSchema } from "@effect/schema"``import { JSONSchema } from "effect" (v3.10+)JSON Schema Draft 2020-12Effect Schema generates Draft-07"thread-local storage""fiber-local storage" via FiberRef (v3) / Context.Reference (v4)fibers are "cancelled"fibers are "interrupted"all queues have back-pressureonly bounded queues; sliding/dropping do notnew MyError("message")``new MyError({ message: "..." }) (Schema errors take objects)
v3-specific hallucinations:
WrongCorrect (v3)Effect.Service (function call)class Foo extends Effect.Service<Foo>()("id", {})``Effect.match(effect, { ... })``Effect.match(effect, { onSuccess, onFailure })``Effect.provide(layer1, layer2)``Effect.provide(Layer.merge(layer1, layer2))
v4-specific hallucinations (AI may mix v3/v4):
Wrong (v3 API used in v4 code)Correct (v4)Context.Tag("X") (v3 shape)Context.Service<X>(id) or class syntaxServiceMap.Service / ServiceMap.ReferenceRenamed back to Context.Service / Context.Reference on 2026-04-07Effect.catchAll(fn)``Effect.catch(fn)``Effect.fork(effect)``Effect.forkChild(effect)``Effect.forkDaemon(effect)``Effect.forkDetach(effect)``Data.TaggedError``Schema.TaggedErrorClass``FiberRef.get(ref)``yield* References.X (a Context.Reference)yield* ref (Ref as Effect)yield* Ref.get(ref) (Ref is no longer an Effect)yield* fiber (Fiber as Effect)yield* Fiber.join(fiber) (Fiber is no longer Effect)Logger.Default / Logger.Live``Logger.layer (v4 naming convention)Schema.TaggedError``Schema.TaggedErrorClass``Schema.makeUnsafe(input)``Schema.make(input) (throws SchemaError); also instance methods schema.makeOption(...), schema.makeEffect(...)``ParseResult (from "effect")SchemaIssue module + SchemaError class; narrow with Schema.isSchemaError``HttpApiEndpoint.get(n, p).pipe(HttpApiEndpoint.setPath(...), setPayload(...), setSuccess(...))``HttpApiEndpoint.get(n, p, { params, query, payload, success, error }) (object-option form)Otlp.layer({ url, serviceName })``OtlpTracer.layer({ url, resource: { serviceName } }) + OtlpSerialization.layerJson + FetchHttpClient.layer``import { HttpApi } from "@effect/platform" (v4)import { HttpApi } from "effect/unstable/httpapi"HttpApi endpoint schema errors are typed errors by defaultIn current v4 betas they default to defects unless transformed
Read references/llm-corrections.md for the exhaustive corrections table.
Read only the reference files relevant to your task:
references/error-modeling.mdreferences/dependency-injection.mdLayerMap) → references/dependency-injection.mdManagedRuntime) → references/dependency-injection.mdreferences/retry-scheduling.mdreferences/concurrency.mdreferences/concurrency.mdExecutionPlan) → references/effect-ai.md / references/retry-scheduling.mdreferences/streams.mdreferences/streams.mdreferences/concurrency.mdreferences/resource-management.mdreferences/resource-management.mdRcRef/ RcMap) → references/resource-management.mdreferences/schema.mdBrand) → references/schema.mdreferences/observability.mdreferences/http.mdreferences/http.md (covers both client and server)references/http.mdreferences/effect-ai.mdreferences/configuration.mdreferences/sql.mdreferences/cli.mdreferences/rpc.mdreferences/distributed.mdTx*) → references/stm.mdreferences/datetime.mdreferences/optics.mdreferences/graph.mdMatch) → references/core-patterns.mdPool) → references/resource-management.mdreferences/concurrency.mdreferences/testing.mdreferences/testing.mdreferences/migration-async.mdreferences/migration-v4.mdreferences/core-patterns.mdreferences/llm-corrections.mdpackage.json before writing any codeEffect valuesEffect.gen for sequential logic, pipelines for simple transforms. In v4, prefer Effect.fn("name") for named functionsE channel; treat bugs as defectsScope when opening/closing things (files, connections, etc.)NodeRuntime.runMain or ManagedRuntime)Start with these ~20 functions (the official recommended set):
Creating effects: Effect.succeed, Effect.fail, Effect.sync, Effect.tryPromise
Composition: Effect.gen (+ Effect.fn in v4), Effect.andThen, Effect.map, Effect.tap, Effect.all
Running: Effect.runPromise, NodeRuntime.runMain (preferred for entry points)
Error handling: Effect.catchTag, Effect.catch (v4) / Effect.catchAll (v3), Effect.orDie
Resources: Effect.acquireRelease, Effect.acquireUseRelease, Effect.scoped
Dependencies: Effect.provide, Effect.provideService
Key modules: Effect, Schema, Layer, Option, Result (v4) / Either (v3), Array, Match
DI (v4): Context.Service, Context.Reference, Layer.effect, Effect.fn("name") DI (v3): Context.Tag, Context.Reference
Always use barrel imports from "effect":
typescript
import { Context, Effect, Schema, Layer, Option, Stream } from "effect"
For companion packages, import from the package name. v3 and v4 differ here:
typescript
// v4 (recommended) - platform transports still separate, but HttpApi / observability
// moved under effect/unstable/*
import { NodeRuntime } from "@effect/platform-node"
import { FetchHttpClient } from "effect/unstable/http"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiBuilder, HttpApiScalar } from "effect/unstable/httpapi"
import { OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability"
// v3 (stable) companion packages
import { NodeRuntime } from "@effect/platform-node"
import { HttpClient } from "@effect/platform"
import { NodeSdk } from "@effect/opentelemetry"
Avoid deep module imports ( effect/Effect) unless your bundler requires it for tree-shaking.
Effect.gen (imperative) for multi-step logic; pipelines for transformsEffect.fn("name") instead of bare Effect.gen for named functions; use Effect.fnUntraced for internal helpers that don't need a span/stack-frameEffect.runPromise / Effect.runSync inside library code - only at program edgesNodeRuntime.runMain for CLI/server entry points (handles SIGINT gracefully)ManagedRuntime when integrating Effect into non-Effect frameworks (Hono, Express, etc.)return yield* when raising an error in a generator (ensures TS understands control flow)Effect.map((x) => fn(x)) not Effect.map(fn) (generics get erased)Effect<A, E, R> shape when it helps design decisionsBefore outputting Effect code, verify:
"effect" (not @effect/schema, @effect/io, etc.)E; unexpected failures are defectsrun* is called only at program edges, not inside library codeacquireRelease are wrapped in Effect.scopedR requirements)yield* (not yield without *)return yield* pattern