# Services

A **service** is a typed dependency: an interface plus a context key that lets
Effect find its implementation at runtime. In Effect v4 you declare one by
extending `Context.Service`, passing the class as the first type parameter and
the service's shape as the second. By convention the implementation lives on a
static `layer`, so the whole service — interface, key, and how to build it —
stays in one file.

```ts
// file: src/db/Database.ts
import { Context, Effect, Layer, Schema } from "effect"

// Errors are schema-defined tagged errors. `Schema.Defect` carries an unknown
// underlying cause (e.g. a thrown driver error) in a typed field.
export class DatabaseError extends Schema.TaggedErrorClass<DatabaseError>()(
  "DatabaseError",
  { cause: Schema.Defect }
) {}

// The first type param is the class itself (the context key); the second is the
// service's interface. The string id should be unique — prefix it with your
// package and the file path.
export class Database extends Context.Service<Database, {
  query(sql: string): Effect.Effect<ReadonlyArray<unknown>, DatabaseError>
}>()("myapp/db/Database") {
  // The implementation is built lazily by a Layer. `Layer.effect` runs an
  // Effect once, when the layer is built, and stores the result as the service.
  static readonly layer = Layer.effect(
    Database,
    Effect.gen(function*() {
      // Functions that return Effects are written with `Effect.fn` so they get
      // a span/name — never a plain function that returns `Effect.gen(...)`.
      const query = Effect.fn("Database.query")(function*(sql: string) {
        yield* Effect.log(`Executing: ${sql}`)
        return [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
      })

      // `Database.of` constructs an instance that satisfies the interface — it
      // gives you type checking on the object you return.
      return Database.of({ query })
    })
  )
}
```

Using the service is symmetric: `yield*` the class to get the implementation,
then call its methods. The requirement is tracked in the effect's type until
the layer is provided.

```ts
// file: src/main.ts
import { Effect } from "effect"
import { Database } from "./db/Database.ts"

const program = Effect.gen(function*() {
  const db = yield* Database
  const users = yield* db.query("SELECT * FROM users")
  yield* Effect.log(`Found ${users.length} users`)
})

// `program` has type Effect<void, DatabaseError, Database>. Provide the layer to
// discharge the `Database` requirement, then run it.
Effect.runFork(program.pipe(Effect.provide(Database.layer)))
```

## How it works

- **The class is the key.** `Context.Service<Self, Shape>()("id")` returns a
  class whose runtime identity is the string `id`. Two services with the same
  id occupy the same slot in the context, so keep ids unique.
- **The class is also an Effect.** A service key is a yieldable
  `Effect<Shape, never, Self>` — that is what makes `yield* Database` work. It
  reaches into the surrounding context and returns the stored implementation. If
  no `Database` was provided, the program won't type-check at the point you try
  to run it.
- **`Self` is repeated** in `Context.Service<Self, Shape>()(...)` because the
  class refers to itself as its own identifier type. The first type argument is
  the class you are defining; the empty `()` then takes the string id (and
  optional `make`). This two-stage call exists so TypeScript can infer the id as
  a literal type.
- **`Database.of(impl)`** is an identity function that exists purely for type
  inference — it checks `impl` against the declared interface.

## Accessing a service without a generator

Outside of `Effect.gen`, two helpers let you reach a service inline. They return
an effect that still carries the service requirement:

```ts
import { Effect } from "effect"
import { Database } from "./db/Database.ts"

// `use` for an effectful access...
const rows = Database.use((db) => db.query("SELECT 1"))

// ...`useSync` when the accessor returns a plain value, not an effect.
const queryFn = Database.useSync((db) => db.query)
```
**Tip:** When a service needs a default rather than a required provision — a feature
flag, a config value, a logger that falls back to the console — reach for
[`Context.Reference`](https://effect.plants.sh/services-and-layers/references/) instead. Use
`Context.Service` when omitting the dependency should be a compile error.

## Services that depend on other services

A service's `layer` is an ordinary Effect, so it can `yield*` other services it
needs. Those become requirements of the layer, which you satisfy when you
compose it — see [Layer composition](https://effect.plants.sh/services-and-layers/layer-composition/).

```ts
import { Context, Effect, Layer } from "effect"
import { Database } from "./db/Database.ts"

export class UserRepo extends Context.Service<UserRepo, {
  countUsers: Effect.Effect<number>
}>()("myapp/UserRepo") {
  static readonly layer = Layer.effect(
    UserRepo,
    Effect.gen(function*() {
      // Depending on Database here makes `Database` a requirement of this layer.
      const db = yield* Database

      const countUsers = Effect.gen(function*() {
        const rows = yield* db.query("SELECT * FROM users")
        return rows.length
      })

      return UserRepo.of({ countUsers })
    })
  // `Layer.provide` feeds Database in, so the resulting layer needs nothing.
  ).pipe(Layer.provide(Database.layer))
}
```

## The three forms of `Context.Service`

`Context.Service<Self, Shape>()(...)` accepts three shapes of arguments. The
first is the common case shown above; the other two let you attach the build
effect directly to the class as a static `make`, which you then hand to
`Layer.effect`.

The id with no options. There is **no** built-in layer or `make` — you define
the implementation separately (the convention is a static `layer`). This is the
form used in every example above.

```ts
import { Context, Effect } from "effect"

export class Clock extends Context.Service<Clock, {
  now: Effect.Effect<number>
}>()("myapp/Clock") {}

// You provide the implementation later, e.g. with Layer.succeed / Layer.effect,
// or store it on a static `layer` as a convention.
```

Pass `{ make }` where `make` is an `Effect`. The class gains a static `make`
property holding that effect; build the layer with `Layer.effect`.

```ts
import { Context, Effect, Layer } from "effect"

export class Clock extends Context.Service<Clock, {
  now: () => number
}>()("myapp/Clock", {
  // `make` is the effect that builds the implementation.
  make: Effect.succeed({ now: () => Date.now() })
}) {
  // Build a layer from the attached `make` effect.
  static readonly layer = Layer.effect(Clock, Clock.make)
}
```

Pass `{ make }` where `make` is a function `(...args) => Effect`. The static
`make` becomes that factory, so callers parameterize how the service is built.

```ts
import { Context, Effect, Layer } from "effect"

export class Greeter extends Context.Service<Greeter, {
  hi: () => string
}>()("myapp/Greeter", {
  // A factory: arguments parameterize the build effect.
  make: (name: string) => Effect.succeed({ hi: () => `hi ${name}` })
}) {
  // Call the factory to get the build effect, then wrap it in a layer.
  static readonly layer = (name: string) =>
    Layer.effect(Greeter, Greeter.make(name))
}
```
**Note:** The `make` option only attaches a static `make` (an effect or a factory) to the
class — it does **not** auto-generate a `.layer`. You always pass `make` to a
`Layer.*` constructor yourself. Many codebases skip the `make` option entirely
and just write `static readonly layer = Layer.effect(...)` inline, which keeps
the building effect (and its dependencies) in one place.

## Service members reference

These members live on the class returned by `Context.Service`. Each is also part
of the `Context.Service` / `Context.Key` interfaces.

### `.make`

The build effect (or factory) you passed via the `make` option. Absent unless
you provided it. Feed it to a `Layer.*` constructor.

```ts
import { Context, Effect, Layer } from "effect"

class Config extends Context.Service<Config, { port: number }>()("Config", {
  make: Effect.succeed({ port: 8080 })
}) {}

const layer = Layer.effect(Config, Config.make)
// => Layer<Config>
```

### `.layer`

Not a built-in member — it is the **convention** of attaching the layer as a
static property. Define it yourself; it is what `Effect.provide` consumes.

```ts
import { Context, Effect, Layer } from "effect"

class Config extends Context.Service<Config, { port: number }>()("Config") {
  static readonly layer = Layer.succeed(Config, { port: 8080 })
}

Effect.runSync(Effect.provide(Config, Config.layer)).port
// => 8080
```

### `Service.of(impl)`

Identity helper: returns `impl` unchanged, but type-checks it against the
service interface. Use it when constructing the implementation object so a wrong
shape is a compile error.

```ts
import { Context } from "effect"

class Cache extends Context.Service<Cache, {
  get: (k: string) => string
}>()("Cache") {}

const impl = Cache.of({ get: (k) => `v:${k}` })
// => { get: (k: string) => string }   (now checked against the interface)
```

### `Service.context(impl)`

Builds a one-service `Context` from an implementation — a shortcut for
`Context.make(Service, impl)`.

```ts
import { Context } from "effect"

class Cache extends Context.Service<Cache, {
  get: (k: string) => string
}>()("Cache") {}

const ctx = Cache.context({ get: (k) => `v:${k}` })
Context.get(ctx, Cache).get("a")
// => "v:a"
```

### `Service.use(f)`

Retrieves the service from the current context and applies an **effectful**
function `f`, in one step. The result keeps the service requirement.

```ts
import { Context, Effect } from "effect"

class Cache extends Context.Service<Cache, {
  get: (k: string) => Effect.Effect<string>
}>()("Cache") {}

const value = Cache.use((c) => c.get("x"))
// => Effect<string, never, Cache>
```

### `Service.useSync(f)`

Like `use`, but `f` returns a plain value rather than an effect. Useful for
pulling out a method or a field.

```ts
import { Context } from "effect"

class Cache extends Context.Service<Cache, {
  get: (k: string) => string
}>()("Cache") {}

const getter = Cache.useSync((c) => c.get)
// => Effect<(k: string) => string, never, Cache>
```

### `.key`

The string identifier you passed in. This is the runtime slot the service
occupies in a context.

```ts
import { Context } from "effect"

class Cache extends Context.Service<Cache, { get: () => string }>()("myapp/Cache") {}

Cache.key
// => "myapp/Cache"
```

### `["Service"]` and `["Identifier"]`

Type-only fields on the key carrying the service shape and identifier. Index into
the class type to recover the interface without redeclaring it.

```ts
import { Context, Effect } from "effect"

class Database extends Context.Service<Database, {
  query(sql: string): Effect.Effect<ReadonlyArray<unknown>>
}>()("Database") {}

type DatabaseService = Database["Service"]
// => { query(sql: string): Effect.Effect<ReadonlyArray<unknown>> }
```

## Manual context manipulation

Everything below operates on the `Context` value and service keys directly. **You
rarely need these** — `Layer` and `Effect.provide` build and thread the context
for you. They are useful for tests, adapters, and tooling that inspect or
assemble a context by hand. For building applications, prefer
[layers](https://effect.plants.sh/services-and-layers/managing-layers/).

For the entire section, assume these keys (a function-style key uses
`Context.Service<Shape>("id")` with a single type argument and no `()`):

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")
```

### `Context.make(key, impl)`

Creates a new `Context` holding a single service.

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")

const ctx = Context.make(Port, { PORT: 8080 })
Context.get(ctx, Port)
// => { PORT: 8080 }
```

### `Context.empty()`

The empty context — no services. Useful as a starting point or a default.

```ts
import { Context } from "effect"

Context.isContext(Context.empty())
// => true
```

### `Context.add(self, key, impl)`

Returns a new context with one more service added (replacing any existing entry
for the same key). Pipeable.

```ts
import { Context, pipe } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = pipe(
  Context.make(Port, { PORT: 8080 }),
  Context.add(Timeout, { TIMEOUT: 5000 })
)
Context.get(ctx, Timeout)
// => { TIMEOUT: 5000 }
```

### `Context.get(self, key)`

Reads a service. The context type must prove the service is present, so this is
the type-safe getter.

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")

Context.get(Context.make(Port, { PORT: 8080 }), Port)
// => { PORT: 8080 }
```

### `Context.getOption(self, key)`

Reads a service as an `Option`. Returns `Option.none()` when a regular key is
absent; for a `Context.Reference` returns `Option.some` of its default.

```ts
import { Context, Option } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = Context.make(Port, { PORT: 8080 })
Context.getOption(ctx, Port) // => Option.some({ PORT: 8080 })
Context.getOption(ctx, Timeout) // => Option.none()
```

### `Context.getOrElse(self, key, orElse)`

Reads a service, evaluating `orElse` for a missing regular key. (A missing
`Context.Reference` resolves to its default instead of the fallback.)

```ts
import { Context } from "effect"

const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

Context.getOrElse(Context.empty(), Timeout, () => ({ TIMEOUT: 1000 }))
// => { TIMEOUT: 1000 }
```

### `Context.getOrUndefined(self, key)`

Raw map lookup: returns the stored value or `undefined`. Does **not** resolve
`Context.Reference` defaults.

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")

Context.getOrUndefined(Context.empty(), Port)
// => undefined
```

### `Context.merge(self, that)`

Combines two contexts into one. On a key collision, `that` wins.

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = Context.merge(
  Context.make(Port, { PORT: 8080 }),
  Context.make(Timeout, { TIMEOUT: 5000 })
)
Context.get(ctx, Timeout)
// => { TIMEOUT: 5000 }
```

### `Context.mergeAll(...ctxs)`

Merges a variadic list of contexts; the last context with a given key wins.

```ts
import { Context } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = Context.mergeAll(
  Context.make(Port, { PORT: 8080 }),
  Context.make(Timeout, { TIMEOUT: 5000 })
)
Context.get(ctx, Port)
// => { PORT: 8080 }
```

### `Context.pick(...keys)`

Returns a context containing only the listed services (an allowlist). Pipeable.

```ts
import { Context, Option, pipe } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = pipe(
  Context.make(Port, { PORT: 8080 }),
  Context.add(Timeout, { TIMEOUT: 5000 }),
  Context.pick(Port)
)
Context.getOption(ctx, Timeout)
// => Option.none()
```

### `Context.omit(...keys)`

Returns a context with the listed services removed (a denylist). Pipeable.

```ts
import { Context, Option, pipe } from "effect"

const Port = Context.Service<{ PORT: number }>("Port")
const Timeout = Context.Service<{ TIMEOUT: number }>("Timeout")

const ctx = pipe(
  Context.make(Port, { PORT: 8080 }),
  Context.add(Timeout, { TIMEOUT: 5000 }),
  Context.omit(Timeout)
)
Context.getOption(ctx, Timeout)
// => Option.none()
```

### `Context.isContext(u)`

Type guard: is the value a `Context`? Does not check which services it holds.

```ts
import { Context } from "effect"

Context.isContext(Context.empty()) // => true
Context.isContext({}) // => false
```

### `Context.isKey(u)`

Type guard: is the value a service key (`Context.Service` or
`Context.Reference`)?

```ts
import { Context } from "effect"

Context.isKey(Context.Service("S")) // => true
Context.isKey(Context.empty()) // => false
```

### `Context.isReference(u)`

Type guard: is the value specifically a `Context.Reference` (a key with a
default value)?

```ts
import { Context } from "effect"

const LoggerRef = Context.Reference("Logger", {
  defaultValue: () => ({ log: (msg: string) => console.log(msg) })
})

Context.isReference(LoggerRef) // => true
Context.isReference(Context.Service("S")) // => false
```
**Caution:** The functions ending in `Unsafe` (`Context.getUnsafe`, `Context.makeUnsafe`,
`Context.getReferenceUnsafe`) bypass the type-level requirement tracking and can
throw or share mutable state. Reach for them only in low-level tooling.

Next: give a service a default value with
[References](https://effect.plants.sh/services-and-layers/references/), or learn the full set of layer
constructors in [Managing layers](https://effect.plants.sh/services-and-layers/managing-layers/).