Effect 4.0 Reference Skill
Comprehensive reference for building applications with Effect 4.0 (TypeScript). Use this skill when writing, reviewing, or refactoring code that uses the effect package.
When to Load Docs
Use the decision tree below to determine which doc files to read. Always start with the most relevant file for the user's task. Read additional files only as needed.
Doc Files
| File | Topics | Read When |
|---|---|---|
docs/01-core-effect.md | Effect type, pipe/flow, Effect.gen, Result, Exit, Cause, Scope, error handling | Writing or understanding core Effect code, error handling, resource management |
docs/02-services-layers.md | ServiceMap.Service, Layer, Config, ConfigProvider, ManagedRuntime | Defining services, dependency injection, layer composition, configuration |
docs/03-data-types.md | Option, Result, Array, Chunk, HashMap, HashSet, Duration, DateTime, Data, Brand, Order, Equivalence | Working with Effect data types, collections, domain modeling |
docs/04-concurrency.md | Fiber, FiberHandle, FiberMap, FiberSet, Ref, SynchronizedRef, SubscriptionRef, Deferred, Queue, PubSub, Pool, Cache, ScopedCache, Semaphore, Latch, Schedule | Concurrency, parallelism, synchronization, queues, caching, scheduling |
docs/05-streaming.md | Stream, Sink, Channel, Pull | Streaming data, pull-based processing, stream composition |
docs/06-schema.md | Schema, SchemaAST, SchemaParser, validation, parsing, serialization | Data validation, parsing, encoding/decoding, API schemas |
docs/07-transactions.md | TxRef, TxHashMap, TxHashSet, TxQueue, TxSemaphore, Effect.atomic | Software transactional memory, atomic operations, STM migration |
docs/08-patterns.md | RcRef, RcMap, ScopedRef, LayerMap, ManagedRuntime, Match, composition patterns | Resource lifecycle, pattern matching, best practices, "which module should I use" |
docs/09-migration.md | v3 to v4 migration, all breaking changes, rename tables | Migrating from Effect v3, understanding what changed |
docs/10-ecosystem.md | @effect/platform-*, @effect/vitest, @effect/opentelemetry, testing, TestClock, unstable modules: HTTP, HTTP API, RPC, SQL, CLI, AI, Cluster, Workflow | Platform setup, testing, observability, HTTP servers/clients, database access, CLI tools, AI integration, distributed systems |
Decision Tree
What is the user doing?
│
├─ Writing/reading core Effect code (Effect.gen, pipe, map, flatMap)
│ └─ Read: docs/01-core-effect.md
│
├─ Defining services, layers, or dependency injection
│ └─ Read: docs/02-services-layers.md
│
├─ Working with Option, Result, collections, or domain types
│ └─ Read: docs/03-data-types.md
│
├─ Concurrency (fibers, refs, queues, semaphores, scheduling)
│ └─ Read: docs/04-concurrency.md
│
├─ Streaming data (Stream, Sink, Channel)
│ └─ Read: docs/05-streaming.md
│
├─ Validation, parsing, or Schema
│ └─ Read: docs/06-schema.md
│
├─ Transactions or STM
│ └─ Read: docs/07-transactions.md
│
├─ Resource management patterns, pattern matching, "which module?"
│ └─ Read: docs/08-patterns.md
│
├─ Migrating from v3, understanding renames
│ └─ Read: docs/09-migration.md
│
├─ Testing, platform setup, ecosystem packages
│ └─ Read: docs/10-ecosystem.md
│
├─ HTTP server/client, API definitions, RPC, SQL, CLI, AI, Cluster, Workflow
│ └─ Read: docs/10-ecosystem.md (unstable modules section)
│
└─ Not sure / general question
└─ Read: docs/01-core-effect.md, then others as needed
Critical v4 Rules
When generating Effect 4.0 code, always follow these rules:
- Services use
ServiceMap.Service, notContext.TagorEffect.Tag Ref,Deferred,Fiberare NOT Effect subtypes -- useRef.get(),Deferred.await(),Fiber.join()Effect.forkis nowEffect.forkChild,Effect.forkDaemonis nowEffect.forkDetachEffect.catchAllis nowEffect.catch,Effect.catchAllCauseis nowEffect.catchCauseEitheris nowResult-- constructors:Result.succeed(value),Result.fail(error). Fields:.success,.failure. Tags:"Success","Failure"FiberRefis removed -- useServiceMap.Reference/References.*- Schema is in core
effectpackage -- no@effect/schemaimport - Layer naming convention: use
.layernot.Defaultor.Live - Generator
this: useEffect.gen({ self: this }, function*() { ... })notEffect.gen(this, function*() { ... }) - Cause is flat:
cause.reasonsarray, not a recursive tree - Tagged errors with fields: use
Schema.TaggedErrorClass<Self>()("Tag", { field: Schema.String }), NOTData.TaggedError("Tag")<{ field: string }>(the<{}>generic syntax breaks in v4 types). Errors without fields can still useData.TaggedError("Tag"). - Schema.Union takes an array:
Schema.Union([A, B])notSchema.Union(A, B) - Schema.Literal is single-value: use
Schema.Literals(["a", "b"])for multiple literals, notSchema.Literal("a", "b") - Schema.decodeUnknown → Schema.decodeUnknownEffect (the Effect-returning variant was renamed;
decodeUnknownSyncis unchanged) - Schema.Class.make → Schema.Class.makeUnsafe
@effect/platformis removed -- importHttpClient,HttpBody,HttpClientRequest,FetchHttpClientfromeffect/unstable/http- LogLevel is a string union (
"Info","Error", etc.), not an object with.label - Logger.replace is removed -- use
Logger.layer([myLogger])to provide a custom logger - Effect.zipRight → Effect.andThen, Effect.firstSuccessOf → Effect.raceAll, Schedule.upTo → Schedule.compose(Schedule.recurs(n))
- Brand.make → callable:
Schema.brand("X")produces a schema;Brand.nominal<T>()produces a callable constructor (UserId("123")notUserId.make("123")) - Config is NOT an Effect subtype --
ConfigisYieldable(works withyield*) but CANNOT be passed toEffect.orDie,Effect.map, etc. Wrap inEffect.genfirst. class extends Schema.Struct({...})breaks -- this pattern (distinct fromSchema.Class) is invalid in v4. Convert toconst MySchema = Schema.Struct({...})with a separatetype MySchema = Schema.Type<typeof MySchema>.Effect.tryPromise(async () => v)bare overload removed -- must useEffect.tryPromise({ try: ..., catch: ... })object form.Effect.tapcallback must return Effect --Effect.tap(voidFn)breaks; wrap asEffect.tap((x) => Effect.sync(() => voidFn(x))).Schema.Objectis removed -- useSchema.Unknowninstead.Schema.transform→Schema.decodeTo-- decode/encode must be wrapped inSchemaGetter.transform(fn).Effect.orDieWith(f)is removed -- useEffect.mapError(f)thenEffect.orDiechained.- Namespace flattening:
Effect.Effect.Error<T>→Effect.Error<T>,Effect.Effect.Success<T>→Effect.Success<T>,Layer.Layer.Success<T>removed,ManagedRuntime.ManagedRuntime.Context<T>removed. Span.parentis no longer yieldable -- it's a plain property that may beundefined. Guard withif (span.parent)before access.
Migration Workflow
When migrating a codebase from v3 to v4, always read docs/09-migration.md first. It contains a phased checklist. The recommended order is:
- Packages first (update versions, remove
@effect/platformand@effect/schema) - Services second (these are the foundation; everything else depends on them)
- Error classes third (
Data.TaggedError→Schema.TaggedErrorClass) - API renames fourth (bulk find-and-replace for
catchAll,decodeUnknown,Union, etc.) - Logger/runtime last (these are leaf concerns)
- Verify: typecheck → tests → bundle size