Learn how to define and use services in Effect v4 for modular, testable code
Services are the primary way to structure Effect applications. They encapsulate behavior, ensure modularity, and make your code testable by allowing dependencies to be easily swapped.
The default way to define a service is to extend ServiceMap.Service, passing in the service interface as a type parameter:
import { Effect, Layer, Schema, ServiceMap } from "effect"class DatabaseError extends Schema.TaggedErrorClass<DatabaseError>()("DatabaseError", { cause: Schema.Defect}) {}// Pass in the service class name as the first type parameter, and the service// interface as the second type parameter.export class Database extends ServiceMap.Service<Database, { query(sql: string): Effect.Effect<Array<unknown>, DatabaseError>}>()() // The string identifier for the service, which should include the package // name and the subdirectory path to the service file. "myapp/db/Database") { // Attach a static layer to the service, which will be used to provide an // implementation of the service. static readonly layer = Layer.effect( Database, Effect.gen(function*() { // Define the service methods using Effect.fn const query = Effect.fn("Database.query")(function*(sql: string) { yield* Effect.log("Executing SQL query:", sql) return [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }] }) // Return an instance of the service using Database.of, passing in an // object that implements the service interface. return Database.of({ query }) }) )}// If you ever need to access the service type, use `Database["Service"]`export type DatabaseService = Database["Service"]
Once defined, you can use a service in your Effect code by yielding it:
import { Effect } from "effect"const program = Effect.gen(function*() { // Acquire the Database service from the environment const db = yield* Database // Use the service methods const results = yield* db.query("SELECT * FROM users") yield* Effect.log("Found users:", results) return results})// The program requires Database in its environment// Type: Effect<Array<unknown>, DatabaseError, Database>
The service dependency is tracked in the type signature. You’ll see Database in the requirements type parameter.