A service captures its construction dependencies
A service is a named interface. A Layer describes how to build a service and supply its dependencies. A context holds supplied service implementations.¶
Build a service once with the dependencies its implementation needs. Return methods that use those captured values. Callers then require only the service.¶
Name the job before the implementation
Context.Service names a service and describes its interface. Effect.Effect<FileStats, FileStatsError> declares the method’s success and expected failure36. Its omitted requirement parameter is never.¶
export class FileInspector extends Context.Service<
FileInspector,
{
readonly inspect: (
path: string
) => Effect.Effect<FileStats, FileStatsError>;
}
>()("@rat-stack/core/FileInspector", {
make: Effect.gen(function* makeFileInspector() {
const fileSystem = yield* FileSystem.FileSystem;make describes service construction as an Effect. Layer.effect runs that construction when the service graph is built.¶
Compose work inside the method
Use Effect.gen for inline composition. Use Effect.fn("name") for reusable functions that need a tracing boundary.
Use Effect.fnUntraced when tracing is not useful.
Do not create a function that only returns another Effect.gen wrapper.¶
const inspect = Effect.fn("FileInspector.inspect")(function* inspect(
path: string
) {
const content = yield* fileSystem
.readFile(path)
.pipe(
Effect.mapError(
(error) => new FileStatsError({ path, reason: error.message })
)
);
return summarizeBytes(path, content);
});
return { inspect } as const;
}),
}) {
static readonly layer = Layer.effect(this, this.make);
}inspect retains the filesystem value captured during construction. It keeps read failures typed and returns a domain result.¶
The service method composes Effects. It does not run a separate runtime that executes the work immediately inside the computation.¶
Construction dependencies are not request identity
Methods can retain contextual requirements when the job needs them. A filesystem implementation usually belongs to construction. A current person may belong to a single request.¶
Pass request data explicitly, or keep that requirement visible at the request boundary. Do not capture one request’s identity in a service shared by later requests.¶
Issue #24 records the risk of treating dependency-free methods as universal law.¶
Common wrong approach
Resolving the filesystem inside every inspect call leaves FileSystem in that method’s requirements.
The caller must now know the implementation dependency. Capturing it during construction removes that requirement from the method.¶
Rebuilding the service inside every call also loses the intended construction lifetime. Supply its Layer at the composition root13, the startup code that chooses and supplies implementations.¶
Effect idiom and house rule
- Services describe behavior. Layers supply implementations and resolve construction requirements.¶
- In rat-stack, keep
makeandstatic layerbeside the service. Core owns service interfaces named for application jobs; adapters own provider code.¶ - rat-stack also uses capability projections, cartridge36 packages, and a no-comments rule.¶
See also: domain structure16, Layer composition13, the Layer constructor pattern12, and testing through services22.¶
Read why dependency injection matters14.¶
Sources
- Effect contributors. 2026. Context. Effect 4.0.0.. Effect-TS. Context.Service supports a typed interface and an effectful make operation. Accessed 2026-10-06.
- Effect contributors. 2026. Composing services with the Layer module.. Effect-TS. Construction captures dependencies before returning Effect.fn methods. Accessed 2026-10-06.
- Effect contributors. 2026. Effect. Effect 4.0.0.. Effect-TS. Effect.gen composes inline work; fn names traced functions; fnUntraced avoids tracing. Accessed 2026-10-06.
- rat-stack contributors. 2026. FileInspector.. rat-stack. The service captures FileSystem in make and exposes an inspect method without filesystem requirements. Accessed 2026-10-06.
- Langton, Kit. 2026. Services & Layers. Effect Solutions.. Kit Langton. Topic framing for service interfaces, dependency capture, and replaceable implementations; examples checked against Effect 4.0.0. Accessed 2026-10-06.
- Effect Solutions contributors. 2025. Clarify that there could be exceptions on methods having dependencies.. Effect Solutions. Reader concern about request-time context and universal dependency-free method advice. Accessed 2026-10-06.
Last changed 2026-10-07 in 989f258. Source on GitHub. Change log.
Linked from
- Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
A service captures its construction dependencies — Build a service with its dependencies, then expose methods that callers can use without rebuilding the graph.
- Change log. What changed in the files served here, newest first.
A service captures its construction dependencies — edited: fix(lore): re-pin the CLI failure excerpt and link glossary first uses
- Configuration is a supplied, validated dependency. Parse configuration when a Layer builds, reject invalid values, and supply controlled settings in tests.
See also: services, Layer composition, failures, and tests.¶
- Dependency injection is the reason to choose Effect. Effect tracks service requirements in types and supplies replaceable implementations through Layers.
Read services that capture dependencies.¶
- Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.
Read service construction, Layer composition, and context and requirements.¶
- Effect keeps the surfaces on one contract. Schema owns values, projections build interfaces, and Layers supply implementations.
Start with Effect basics, then construct a service and compose its Layers.¶
- Feature flags. Typed feature flags with owners, removal dates, and stable subject rollouts.
Handlers request the Flags service from core.
- Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
- Layer composition makes dependencies explicit. Supply a service's dependencies, choose which services remain visible, and reuse Layer identity within a build.
See also: service construction, domain structure, cartridges, and testing.¶
- Learn rat-stack from your own agent. Turn on learn mode: your own agent explains rat-stack ideas during real work and keeps progress local.
The first path starts with context and requirements, then how a service captures its dependencies.
- learn-rat-stack. Trace a capability through Effect, XState, five projections, the CLI, and Alchemy. Try hosted search and read.
For implementation tasks, use services, Layer composition, and testing.¶
- Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.
A service captures its construction dependencies — Build a service with its dependencies, then expose methods that callers can use without rebuilding the graph.
- Run Effect at the integration boundary. Build the runtime where a calling framework enters, reuse its services, and dispose it when that integration ends.
Read services before extracting the job from its host.
- Schemas define the boundary. Define accepted data with Schema, decode unknown input before dispatch, and encode results through the declared contract.
See also: one schema, three surfaces, OpenAPI refusals, services, and testing.¶
- Source change history (log.md). The generated change log as Markdown.
A service captures its construction dependencies — edited: fix(lore): re-pin the CLI failure excerpt and link glossary first uses
- Structure an Effect codebase by domain. Start with folders for application work, services and Layers in the same file, and startup code that supplies implementations.
See service construction for the full pattern.¶
Unlinked mentions (49)
- A clean playground → Its database cartridge owns a RunLog service and Layers for two database implementations.¶
- A Layer as constructor → A Layer describes how to build a service and supply its dependencies.
- add-a-capability → A service is a named interface for one job.
- add-a-lifecycle-machine → A service is a named interface for one job.
- add-a-store → A service is a named interface for one job.
- Agent rules for rat-stack (AGENTS.md) → 1 in prepare so the Effect language service diagnostics in tsconfig.base.json fail tsc, not just the editor.
- An MCP your users want → OAuth lets a person authorize a client to access a service.¶
- Analytics → A service is a named interface for one job.¶
- Anti-money → Sam describes Alchemy as “anti-money”: reduce software sold as a service (SaaS) to libraries, then ask what remains valuable to manage.
- Bindings → A service’s configuration and permissions can be declared together before the application runs.
- Build and run rat-stack (README.md) → Put a Worker or Deno runtime behind the same Sandbox service to isolate the network too.
- Capabilities → A service is a named interface for one job.
- Cartridges → A service is the named interface callers use for that job.
- Code snippets quote a pinned source → A service is a named interface.
- Concurrent work needs an owner and a bound → Measure the service’s limits before selecting an operational bound.¶
- Configuration is a supplied, validated dependency → A service is a named interface.
- Database → It gives callers one service, RunLog.
- Dependency injection is the reason to choose Effect → The compiler rejects execution while a required service remains in R.¶
- Devtools → A service is a named interface for one job.¶
- Effect + Alchemy peer patterns → The browser calls a same-origin TanStack /rpc route, which forwards to a private BACKEND service binding; the backend has no public Workers URL.
- Effect 4 study: September 2026 → These projects show Effect service, test, CLI, and lifecycle patterns.
- Effect basics → A service is a named interface for work.
- Effect's design lineage → Dependency injection supplies service implementations to the code that needs them.
- Fence → A service is a named interface for one job.¶
- Hexagonal architecture → Typed preparation for agent-assisted intake uses the same service boundary: IntakeTicket, AbuseScore, and IntakeEvents, question and consent schemas, and test layers live in core.
- HTTP success needs a status check and a decoder → In rat-stack, core owns service interfaces named for application jobs.
- Infrastructure as effects → An Alchemy Layer can declare the cloud resources behind a service.
- keep-or-cut → A service is a named interface for one job.¶
- Layer composition makes dependencies explicit → A service is a named interface.
- learn → terse: show the service declaration and the line that uses or provides it.
- Learn mode presents concepts at useful depths → A service is a named interface for one job.¶
- learn-alchemy → A service is a named interface for one job.
- learn-rat-stack → A service is a named interface for one job.
- Michael Arnaldi → Dependency injection supplies service implementations to callers.
- Purpose and boundaries of rat-stack (VISION.md) → New code takes the rat-stack path: a shared contract, a job-shaped service port, a provider adapter outside core, and an outcome you can observe.
- Rat King binds agents into one encrypted network → Cartridges explain the service and infrastructure pattern.
- rat-stack → Pieces: A service is an interface for one job.
- Rat's Nest keeps the code public and the inventory private → Cartridges explain rat-stack’s service and infrastructure pattern.¶
- Run Effect at the integration boundary → A service is a named interface.
- Schema projections: 2026-09-18 history → Casts live at exactly two boundaries per projection (tuple-to-record and handler record), each with a reason; the two projection files turn off three language-service diagnostics that cannot tell a typed boundary from a leak.
- Scopes release resources when work ends → A service Layer can own that resource for its build lifetime.
- Shared caches hold completed values → rat-stack-patterns/no-shared-pending-cache rejects these cache constructors in module, service, and Worker initialization effects.
- ship → Service: a named interface for one job.¶
- Structure an Effect codebase by domain → A service is a named interface for that work.
- test-behaviour → An example test fits one interface between parts, such as a service over the real filesystem.
- Tests prove behavior through supplied services → A service is a named interface.
- The fence → Effect language-service diagnostics run through TypeScript.
- uncomplect → ts; provide its Layer where the application selects and connects service implementations.¶
- Worker init runs twice → The runtime did not have that deploy-time service, so production returned error 1101 for about three minutes.¶