Configuration is a supplied, validated dependency
A service is a named interface. A Layer describes how to build it and supply its dependencies. Schema defines accepted values and checks data at runtime.ΒΆ
Read configuration when its Layer builds. Expose parsed values through a service rather than reading environment variables throughout domain code.ΒΆ
Define accepted values before reading them
Config.Literals limits APP_ENV to three values. The declared default handles a missing setting.ΒΆ
import { Config } from "effect";
import { ConfigService } from "./config-service.js";
export class AppConfig extends ConfigService.Service<AppConfig>()(
"@rat-stack/core/AppConfig",
{
appEnv: Config.Literals(
["development", "test", "production"],
"APP_ENV"
).pipe(Config.withDefault("development")),
}
) {}The environment name and accepted values live together. The default does not make an invalid supplied value acceptable.ΒΆ
Effectβs Config.schema can describe more complex validated settings.
Use the Schema-backed path instead of writing a second parser for the same domain rule.ΒΆ
Supply another configuration source
A ConfigProvider supplies raw configuration inputs.
Tests can replace the source with fromUnknown while still exercising the production parsing Layer.ΒΆ
const withProvider = (root: Parameters<typeof ConfigProvider.fromUnknown>[0]) =>
Layer.provide(
AppConfig.layer,
ConfigProvider.layer(ConfigProvider.fromUnknown(root))
);
it.effect("reads APP_ENV through the active ConfigProvider", () =>
Effect.gen(function* readsFromProvider() {
const config = yield* AppConfig;
expect(config.appEnv).toBe("test");
}).pipe(Effect.provide(withProvider({ APP_ENV: "test" })))
);The suite also checks rejection:ΒΆ
it.effect("rejects values outside the literal set", () =>
Effect.gen(function* rejectsUnknownLiteral() {
const error = yield* Effect.flip(
Layer.build(withProvider({ APP_ENV: "staging" }))
);
expect(error._tag).toBe("ConfigError");
})
);Supply typed values when parsing is not the task
AppConfig.configLayer accepts already-typed values. It uses Layer.succeed and skips parsing.
Use this for a test about domain behavior. Use a provider when the test is about configuration decoding.ΒΆ
rat-stackβs factory provides these two ways to supply configuration.ΒΆ
Common wrong approach
Reading process.env inside each domain method ties the method to the host and allows inconsistent parsing.
A config service moves that choice to construction and gives tests a service they can replace.ΒΆ
Keep missing settings and rejected settings distinct. Let construction fail when a supplied value violates the schema.ΒΆ
Effect idiom and house rule
- Config parses supplied data and reports typed failures36. ConfigProvider selects the source.ΒΆ
- In rat-stack, declare environment inputs in
.env.schema. Alchemy provider credentials come from profiles. Do not supply them through environment variables.ΒΆ - Do not unwrap a redacted value for logs or public examples.ΒΆ
See also: services16, Layer composition13, failures36, and tests22.ΒΆ
Read why dependency injection matters14.ΒΆ
Sources
- Effect contributors. 2026. Config. Effect 4.0.0.. Effect-TS. Config.Literals, defaults, schema validation, and capitalized Config constructors. Accessed 2026-10-06.
- Effect contributors. 2026. ConfigProvider. Effect 4.0.0.. Effect-TS. Providers replace the config source; fromUnknown and layer support controlled inputs. Accessed 2026-10-06.
- rat-stack contributors. 2026. ConfigService.. rat-stack. The factory provides a parsing Layer and a typed configLayer that bypasses parsing for controlled tests. Accessed 2026-10-06.
- rat-stack contributors. 2026. AppConfig tests.. rat-stack. Tests cover supplied config, a missing-value default, an invalid value, and direct typed configuration. Accessed 2026-10-06.
- Langton, Kit. 2026. Config. Effect Solutions.. Kit Langton. Topic framing for config Layers and replaceable providers; lowercase constructor examples do not match Effect 4.0.0. Accessed 2026-10-06.
Last changed 2026-10-07 in e73c9d9. Source on GitHub. Change log.
Linked from
- Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
Configuration is a supplied, validated dependency β Parse configuration when a Layer builds, reject invalid values, and supply controlled settings in tests.
- Change log. What changed in the files served here, newest first.
Configuration is a supplied, validated dependency β edited: feat(learn): teach the next twenty cards with plain lines, diagrams and snippets
- Dependency injection is the reason to choose Effect. Effect tracks service requirements in types and supplies replaceable implementations through Layers.
Read configuration as a dependency.ΒΆ
- Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.
Configuration: parse supplied settings.ΒΆ
- Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
- Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.
Configuration is a supplied, validated dependency β Parse configuration when a Layer builds, reject invalid values, and supply controlled settings in tests.
- Source change history (log.md). The generated change log as Markdown.
Configuration is a supplied, validated dependency β edited: feat(learn): teach the next twenty cards with plain lines, diagrams and snippets
Unlinked mentions (1)
- Agent rules for rat-stack (AGENTS.md) β ts derives a service from Effect Config (production layer reads the ConfigProvider, configLayer takes parsed values for tests); AppConfig is the instance and mirrors .env.schema.