- Notifications
You must be signed in to change notification settings - Fork14
A community-driven knowledge base of practical patterns for Effect-TS.
License
NotificationsYou must be signed in to change notification settings
PaulJPhilp/EffectPatterns
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Warning
This is an auto-generated file. Manual edits will be overwritten by the publishing pipeline.For project information, seeABOUT.md
A community-driven knowledge base of practical, goal-oriented patterns for building robust applications with Effect-TS.
This repository is designed to be a living document that helps developers move from core concepts to advanced architectural strategies by focusing on the "why" behind the code.
Looking for machine-readable rules for AI IDEs and coding agents? See theAI Coding Rules section below.
- resource-management
- concurrency
- core-concepts
- testing
- domain-modeling
- modeling-data
- building-apis
- error-management
- building-data-pipelines
- making-http-requests
- tooling-and-debugging
- observability
- project-setup--execution
- [Control Flow](#control flow)
| Pattern | Skill Level | Summary |
|---|---|---|
| Creating from Collections | 🟢Beginner | Use fromIterable and fromArray to create Streams or Effects from arrays, iterables, or other collections, enabling batch and streaming operations. |
Safely Bracket Resource Usage withacquireRelease | 🟢Beginner | UseEffect.acquireRelease to guarantee a resource's cleanup logic runs, even if errors or interruptions occur. |
Compose Resource Lifecycles withLayer.merge | 🟡Intermediate | Combine multiple resource-managing layers, letting Effect automatically handle the acquisition and release order. |
| Create a Service Layer from a Managed Resource | 🟡Intermediate | UseLayer.scoped withEffect.Service to transform a managed resource into a shareable, application-wide service. |
Manually Manage Lifecycles withScope | 🟠Advanced | UseScope directly to manage complex resource lifecycles or when building custom layers. |
| Create a Managed Runtime for Scoped Resources | 🟠Advanced | Use Layer.launch to safely manage the lifecycle of layers containing scoped resources, ensuring finalizers are always run. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Creating from Synchronous and Callback Code | 🟢Beginner | Use sync and async to lift synchronous or callback-based computations into Effect, enabling safe and composable interop with legacy code. |
| Race Concurrent Effects for the Fastest Result | 🟡Intermediate | Use Effect.race to run multiple effects concurrently and proceed with the result of the one that succeeds first, automatically interrupting the others. |
| Sequencing with andThen, tap, and flatten | 🟡Intermediate | Use andThen, tap, and flatten to sequence computations, run side effects, and flatten nested structures in Effect, Stream, Option, and Either. |
| Mapping and Chaining over Collections with forEach and all | 🟡Intermediate | Use forEach and all to apply effectful functions to collections and combine the results, enabling batch and parallel processing. |
| Run Independent Effects in Parallel with Effect.all | 🟡Intermediate | Use Effect.all to run multiple independent effects concurrently and collect all their results into a single tuple. |
| Process a Collection in Parallel with Effect.forEach | 🟡Intermediate | Use Effect.forEach with theconcurrency option to process a collection of items in parallel with a fixed limit, preventing resource exhaustion. |
| Manage Shared State Safely with Ref | 🟡Intermediate | Use Ref to model shared, mutable state in a concurrent environment, ensuring all updates are atomic and free of race conditions. |
| Manage Shared State Safely with Ref | 🟡Intermediate | Use Ref to model shared, mutable state in a concurrent environment, ensuring all updates are atomic and free of race conditions. |
| Poll for Status Until a Task Completes | 🟠Advanced | Use Effect.race to run a repeating polling effect alongside a main task, automatically stopping the polling when the main task finishes. |
| Manage Resource Lifecycles with Scope | 🟠Advanced | Use Scope for fine-grained, manual control over resource lifecycles, ensuring cleanup logic (finalizers) is always executed. |
| Run Background Tasks with Effect.fork | 🟠Advanced | Use Effect.fork to start a computation in a background fiber, allowing the parent fiber to continue its work without waiting. |
| Execute Long-Running Apps with Effect.runFork | 🟠Advanced | Use Effect.runFork at the application's entry point to launch a long-running process as a detached fiber, allowing for graceful shutdown. |
| Add Caching by Wrapping a Layer | 🟠Advanced | Implement caching by creating a new layer that wraps a live service, intercepting method calls to add caching logic without modifying the original service. |
| Implement Graceful Shutdown for Your Application | 🟠Advanced | Use Effect.runFork and listen for OS signals (SIGINT, SIGTERM) to trigger a Fiber.interrupt, ensuring all resources are safely released. |
| Decouple Fibers with Queues and PubSub | 🟠Advanced | Use Queue for point-to-point work distribution and PubSub for broadcast messaging to enable safe, decoupled communication between concurrent fibers. |
| Understand Fibers as Lightweight Threads | 🟠Advanced | A Fiber is a lightweight, virtual thread managed by the Effect runtime, enabling massive concurrency on a single OS thread without the overhead of traditional threading. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Understand that Effects are Lazy Blueprints | 🟢Beginner | An Effect is a lazy, immutable blueprint describing a computation, which does nothing until it is explicitly executed by a runtime. |
| Conditional Branching with if, when, and cond | 🟢Beginner | Use combinators like if, when, and cond to express conditional logic declaratively across Effect, Stream, Option, and Either. |
| Filtering Results with filter | 🟢Beginner | Use filter to keep or discard results based on a predicate, across Effect, Stream, Option, and Either. |
| Transforming Values with map | 🟢Beginner | Use map to transform the result of an Effect, Stream, Option, or Either in a declarative, type-safe way. |
| Lifting Values with succeed, some, and right | 🟢Beginner | Use succeed, some, and right to lift plain values into Effect, Option, or Either, making them composable and type-safe. |
| Converting from Nullable, Option, or Either | 🟢Beginner | Use fromNullable, fromOption, and fromEither to convert nullable values, Option, or Either into Effects or Streams, enabling safe and composable interop. |
| Write Sequential Code with Effect.gen | 🟢Beginner | Use Effect.gen with yield* to write sequential, asynchronous code in a style that looks and feels like familiar async/await. |
| Use .pipe for Composition | 🟢Beginner | Use the .pipe() method to chain multiple operations onto an Effect in a readable, top-to-bottom sequence. |
| Transform Effect Values with map and flatMap | 🟢Beginner | Use Effect.map for synchronous transformations and Effect.flatMap to chain operations that return another Effect. |
| Wrap Synchronous Computations with sync and try | 🟢Beginner | Use Effect.sync for non-throwing synchronous code and Effect.try for synchronous code that might throw an exception. |
| Wrap Asynchronous Computations with tryPromise | 🟢Beginner | Use Effect.tryPromise to safely convert a function that returns a Promise into an Effect, capturing rejections in the error channel. |
| Combining Values with zip | 🟢Beginner | Use zip to combine two computations, pairing their results together in Effect, Stream, Option, or Either. |
| Solve Promise Problems with Effect | 🟢Beginner | Understand how Effect solves the fundamental problems of native Promises, such as untyped errors, lack of dependency injection, and no built-in cancellation. |
| Chaining Computations with flatMap | 🟢Beginner | Use flatMap to chain together computations where each step may itself be effectful, optional, or error-prone. |
| Understand the Three Effect Channels (A, E, R) | 🟢Beginner | Learn about the three generic parameters of an Effect: the success value (A), the failure error (E), and the context requirements (R). |
| Create Pre-resolved Effects with succeed and fail | 🟢Beginner | Use Effect.succeed(value) to create an Effect that immediately succeeds with a value, and Effect.fail(error) for an Effect that immediately fails. |
| Comparing Data by Value with Structural Equality | 🟢Beginner | Use Data.struct and Equal.equals to safely compare objects by their value instead of their reference, avoiding common JavaScript pitfalls. |
| Beyond the Date Type - Real World Dates, Times, and Timezones | 🟡Intermediate | Use the Clock service for testable access to the current time and prefer immutable primitives for storing and passing timestamps. |
| Access Configuration from the Context | 🟡Intermediate | Access your type-safe configuration within an Effect.gen block by yielding the Config object you defined. |
| Representing Time Spans with Duration | 🟡Intermediate | Use the Duration data type to represent time intervals in a type-safe, human-readable, and composable way. |
| Define a Type-Safe Configuration Schema | 🟡Intermediate | Use Effect.Config primitives to define a schema for your application's configuration, ensuring type-safety and separation from code. |
| Provide Configuration to Your App via a Layer | 🟡Intermediate | Use Config.layer(schema) to create a Layer that provides your configuration schema to the application's context. |
| Understand Layers for Dependency Injection | 🟡Intermediate | A Layer is a blueprint that describes how to build a service, detailing its own requirements and any potential errors during its construction. |
| Use Chunk for High-Performance Collections | 🟡Intermediate | Use Chunk as a high-performance, immutable alternative to JavaScript's Array, especially for data processing pipelines. |
| Control Flow with Conditional Combinators | 🟡Intermediate | Use combinators like Effect.if, Effect.when, and Effect.cond to handle conditional logic in a declarative, composable way. |
| Process Streaming Data with Stream | 🟡Intermediate | Use Stream<A, E, R> to represent and process data that arrives over time, such as file reads, WebSocket messages, or paginated API results. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Mocking Dependencies in Tests | 🟡Intermediate | Use a test-specific Layer to provide mock implementations of services your code depends on, enabling isolated and deterministic unit tests. |
| Write Tests That Adapt to Application Code | 🟡Intermediate | A cardinal rule of testing: Tests must adapt to the application's interface, not the other way around. Never modify application code solely to make a test pass. |
| Accessing the Current Time with Clock | 🟡Intermediate | Use the Clock service to access the current time in a testable, deterministic way, avoiding direct calls to Date.now(). |
| Use the Auto-Generated .Default Layer in Tests | 🟡Intermediate | When testing, always use the MyService.Default layer that is automatically generated by the Effect.Service class for dependency injection. |
| Organize Layers into Composable Modules | 🟠Advanced | Structure a large application by grouping related services into 'module' layers, which are then composed together with a shared base layer. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Comparing Data by Value with Data.struct | 🟢Beginner | Use Data.struct to create immutable, structurally-typed objects that can be compared by value, not by reference. |
| Working with Tuples using Data.tuple | 🟢Beginner | Use Data.tuple to create immutable, type-safe tuples that support value-based equality and pattern matching. |
| Model Optional Values Safely with Option | 🟢Beginner | Use Option to explicitly represent a value that may or may not exist, eliminating null and undefined errors. |
| Accumulate Multiple Errors with Either | 🟢Beginner | Use Either<E, A> to represent computations that can fail, allowing you to accumulate multiple errors instead of short-circuiting on the first one. |
| Handling Specific Errors with catchTag and catchTags | 🟡Intermediate | Use catchTag and catchTags to recover from or handle specific error types in the Effect failure channel, enabling precise and type-safe error recovery. |
| Matching Tagged Unions with matchTag and matchTags | 🟡Intermediate | Use matchTag and matchTags to pattern match on specific tagged union cases, enabling precise and type-safe branching. |
| Define Contracts Upfront with Schema | 🟡Intermediate | Use Schema to define the types for your data models and function signatures before writing the implementation, creating clear, type-safe contracts. |
| Representing Time Spans with Duration | 🟡Intermediate | Use Duration to represent time intervals in a type-safe, human-readable, and composable way. |
| Transform Data During Validation with Schema | 🟡Intermediate | Use Schema.transform to safely convert data from one type to another during the parsing phase, such as from a string to a Date. |
| Type Classes for Equality, Ordering, and Hashing with Data.Class | 🟡Intermediate | Use Data.Class to derive and implement type classes for equality, ordering, and hashing, enabling composable and type-safe abstractions. |
| Parse and Validate Data with Schema.decode | 🟡Intermediate | Use Schema.decode(schema) to create an Effect that parses and validates unknown data, which integrates seamlessly with Effect's error handling. |
| Define Type-Safe Errors with Data.TaggedError | 🟡Intermediate | Create custom, type-safe error classes by extending Data.TaggedError to make error handling robust, predictable, and self-documenting. |
| Work with Dates and Times using DateTime | 🟡Intermediate | Use DateTime for immutable, time-zone-aware date and time values, enabling safe and precise time calculations. |
| Model Optional Values Safely with Option | 🟡Intermediate | Use Option to explicitly represent a value that may or may not exist, eliminating null and undefined errors. |
| Modeling Validated Domain Types with Brand | 🟡Intermediate | Use Brand to create domain-specific types from primitives, making illegal states unrepresentable and preventing accidental misuse. |
| Modeling Tagged Unions with Data.case | 🟡Intermediate | Use Data.case to create tagged unions (algebraic data types) for robust, type-safe domain modeling and pattern matching. |
| Model Validated Domain Types with Brand | 🟡Intermediate | Use Brand to turn primitive types like string or number into specific, validated domain types like Email or PositiveInt, making illegal states unrepresentable. |
| Use Effect.gen for Business Logic | 🟡Intermediate | Encapsulate sequential business logic, control flow, and dependency access within Effect.gen for improved readability and maintainability. |
| Validating and Parsing Branded Types | 🟡Intermediate | Use Schema and Brand together to validate and parse branded types at runtime, ensuring only valid values are constructed. |
| Distinguish 'Not Found' from Errors | 🟡Intermediate | Use Effect<Option> to clearly distinguish between a recoverable 'not found' case (None) and a true failure (Fail). |
| Accumulate Multiple Errors with Either | 🟡Intermediate | Use Either<E, A> to represent computations that can fail, allowing you to accumulate multiple errors instead of short-circuiting on the first one. |
| Avoid Long Chains of .andThen; Use Generators Instead | 🟡Intermediate | Prefer Effect.gen over long chains of .andThen for sequential logic to improve readability and maintainability. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Working with Immutable Arrays using Data.array | 🟢Beginner | Use Data.array to create immutable, type-safe arrays that support value-based equality and safe functional operations. |
| Work with Immutable Sets using HashSet | 🟡Intermediate | Use HashSet to model immutable, high-performance sets for efficient membership checks and set operations. |
| Work with Arbitrary-Precision Numbers using BigDecimal | 🟡Intermediate | Use BigDecimal for arbitrary-precision decimal arithmetic, avoiding rounding errors and loss of precision in financial or scientific calculations. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Send a JSON Response | 🟢Beginner | Create and send a structured JSON response with the correct headers and status code. |
| Create a Basic HTTP Server | 🟢Beginner | Launch a simple, effect-native HTTP server to respond to incoming requests. |
| Extract Path Parameters | 🟢Beginner | Capture and use dynamic segments from a request URL, such as a resource ID. |
| Handle a GET Request | 🟢Beginner | Define a route that responds to a specific HTTP GET request path. |
| Make an Outgoing HTTP Client Request | 🟡Intermediate | Use the built-in Effect HTTP client to make safe and composable requests to external services from within your API. |
| Handle API Errors | 🟡Intermediate | Translate application-specific errors from the Effect failure channel into meaningful HTTP error responses. |
| Validate Request Body | 🟡Intermediate | Safely parse and validate an incoming JSON request body against a predefined Schema. |
| Provide Dependencies to Routes | 🟡Intermediate | Inject services like database connections into HTTP route handlers using Layer and Effect.Service. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Checking Option and Either Cases | 🟢Beginner | Use isSome, isNone, isLeft, and isRight to check Option and Either cases for simple, type-safe branching. |
| Wrapping Synchronous and Asynchronous Computations | 🟢Beginner | Use try and tryPromise to safely wrap synchronous or asynchronous computations that may throw or reject, capturing errors in the Effect world. |
| Lifting Errors and Absence with fail, none, and left | 🟢Beginner | Use fail, none, and left to represent errors or absence in Effect, Option, or Either, making failures explicit and type-safe. |
| Matching on Success and Failure with match | 🟢Beginner | Use match to handle both success and failure cases in a single, declarative place for Effect, Option, and Either. |
| Retry Operations Based on Specific Errors | 🟡Intermediate | Use Effect.retry and predicate functions to selectively retry an operation only when specific, recoverable errors occur. |
| Leverage Effect's Built-in Structured Logging | 🟡Intermediate | Use Effect's built-in logging functions (Effect.log, Effect.logInfo, etc.) for structured, configurable, and context-aware logging. |
| Handling Errors with catchAll, orElse, and match | 🟡Intermediate | Use catchAll, orElse, and match to recover from errors, provide fallbacks, or transform errors in Effect, Either, and Option. |
| Handle Flaky Operations with Retries and Timeouts | 🟡Intermediate | Use Effect.retry and Effect.timeout to build resilience against slow or intermittently failing operations, such as network requests. |
| Handle Errors with catchTag, catchTags, and catchAll | 🟡Intermediate | Use catchTag for type-safe recovery from specific tagged errors, and catchAll to recover from any possible failure. |
| Modeling Effect Results with Exit | 🟡Intermediate | Use Exit<E, A> to represent the result of running an Effect, capturing both success and failure (including defects) in a type-safe way. |
| Mapping Errors to Fit Your Domain | 🟡Intermediate | Use Effect.mapError to transform specific, low-level errors into more general domain errors, creating clean architectural boundaries. |
| Effectful Pattern Matching with matchEffect | 🟡Intermediate | Use matchEffect to perform effectful branching based on success or failure, enabling rich workflows in the Effect world. |
| Conditionally Branching Workflows | 🟡Intermediate | Use predicate-based operators like Effect.filter and Effect.if to make decisions and control the flow of your application based on runtime values. |
| Control Repetition with Schedule | 🟡Intermediate | Use Schedule to create composable, stateful policies that define precisely how an effect should be repeated or retried. |
| Handle Unexpected Errors by Inspecting the Cause | 🟠Advanced | Use Cause to get rich, structured information about errors and failures, including defects, interruptions, and error traces. |
| Handle Unexpected Errors by Inspecting the Cause | 🟠Advanced | Use Effect.catchAllCause or Effect.runFork to inspect the Cause of a failure, distinguishing between expected errors (Fail) and unexpected defects (Die). |
| Pattern | Skill Level | Summary |
|---|---|---|
| Run a Pipeline for its Side Effects | 🟢Beginner | Execute a pipeline for its effects without collecting the results, saving memory. |
| Collect All Results into a List | 🟢Beginner | Run a pipeline and gather all of its results into an in-memory array. |
| Create a Stream from a List | 🟢Beginner | Turn a simple in-memory array or list into a foundational data pipeline using Stream. |
| Turn a Paginated API into a Single Stream | 🟡Intermediate | Convert a paginated API into a continuous, easy-to-use stream, abstracting away the complexity of fetching page by page. |
| Process Items in Batches | 🟡Intermediate | Group items into chunks for efficient bulk operations, like database inserts or batch API calls. |
| Process a Large File with Constant Memory | 🟡Intermediate | Create a data pipeline from a file on disk, processing it line-by-line without loading the entire file into memory. |
| Automatically Retry Failed Operations | 🟡Intermediate | Build a self-healing pipeline that can automatically retry failed processing steps using a configurable backoff strategy. |
| Process collections of data asynchronously | 🟡Intermediate | Process collections of data asynchronously in a lazy, composable, and resource-safe manner using Effect's Stream. |
| Process Items Concurrently | 🟡Intermediate | Perform an asynchronous action for each item in a stream with controlled parallelism to dramatically improve performance. |
| Manage Resources Safely in a Pipeline | 🟠Advanced | Ensure resources like file handles or connections are safely acquired at the start of a pipeline and always released at the end, even on failure. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Create a Testable HTTP Client Service | 🟡Intermediate | Define an HttpClient service with separate 'Live' and 'Test' layers to enable robust, testable interactions with external APIs. |
| Model Dependencies as Services | 🟡Intermediate | Abstract external dependencies and capabilities into swappable, testable services using Effect's dependency injection system. |
| Build a Basic HTTP Server | 🟠Advanced | Combine Layer, Runtime, and Effect to create a simple, robust HTTP server using Node.js's built-in http module. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Supercharge Your Editor with the Effect LSP | 🟡Intermediate | Install the Effect Language Server (LSP) extension for your editor to get rich, inline type information and enhanced error checking for your Effect code. |
| Teach your AI Agents Effect with the MCP Server | 🟠Advanced | Use the Effect MCP server to provide live, contextual information about your application's structure directly to AI coding agents. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Add Custom Metrics to Your Application | 🟡Intermediate | Use Effect's Metric module to instrument your code with counters, gauges, and histograms to track key business and performance indicators. |
| Trace Operations Across Services with Spans | 🟡Intermediate | Use Effect.withSpan to create custom tracing spans, providing detailed visibility into the performance and flow of your application's operations. |
| Instrument and Observe Function Calls with Effect.fn | 🟡Intermediate | Use Effect.fn to wrap, instrument, and observe function calls, enabling composable logging, metrics, and tracing at function boundaries. |
| Leverage Effect's Built-in Structured Logging | 🟡Intermediate | Use Effect's built-in logging functions for structured, configurable, and context-aware logging. |
| Redact and Handle Sensitive Data | 🟡Intermediate | Use Redacted to securely handle sensitive data, ensuring secrets are not accidentally logged or exposed. |
| Add Custom Metrics to Your Application | 🟡Intermediate | Use Effect's Metric module to instrument your code with counters, gauges, and histograms to track key business and performance indicators. |
| Use Chunk for High-Performance Collections | 🟡Intermediate | Use Chunk as a high-performance, immutable alternative to JavaScript's Array, especially for data processing pipelines. |
| Trace Operations Across Services with Spans | 🟡Intermediate | Use Effect.withSpan to create custom tracing spans, providing detailed visibility into the performance and flow of your application's operations. |
| Integrate Effect Tracing with OpenTelemetry | 🟠Advanced | Connect Effect's tracing spans to OpenTelemetry for end-to-end distributed tracing and visualization. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Execute Asynchronous Effects with Effect.runPromise | 🟢Beginner | Use Effect.runPromise at the 'end of the world' to execute an asynchronous Effect and get its result as a JavaScript Promise. |
| Execute Synchronous Effects with Effect.runSync | 🟢Beginner | Use Effect.runSync at the 'end of the world' to execute a purely synchronous Effect and get its value directly. |
| Set Up a New Effect Project | 🟢Beginner | Initialize a new Node.js project with the necessary TypeScript configuration and Effect dependencies to start building. |
| Create a Reusable Runtime from Layers | 🟠Advanced | Compile your application's layers into a reusable Runtime object to efficiently execute multiple effects that share the same context. |
| Pattern | Skill Level | Summary |
|---|---|---|
| Pattern Match on Option and Either | 🟢Beginner | Use declarative match() combinators to handle optional and error-prone values |
About
A community-driven knowledge base of practical patterns for Effect-TS.
Topics
Resources
License
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
No packages published