# Configuration is a supplied, validated dependency

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [how to burn a trillion tokens and get good results](/tokenmaxx#interested).

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.

packages/core/src/app-config.ts at 65e9465f38092e24486392f22c08f45d61230c20; lines 1-13; highlighted none.

```typescript
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.

## Replace the source, not the parser

A `ConfigProvider` supplies raw configuration inputs.
Tests can replace the source with `fromUnknown` while still exercising the production parsing Layer.

packages/core/test/app-config.test.ts at 65e9465f38092e24486392f22c08f45d61230c20; lines 6-17; highlighted none.

```typescript
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:

packages/core/test/app-config.test.ts at 65e9465f38092e24486392f22c08f45d61230c20; lines 26-34; highlighted none.

```typescript
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 replacement boundary.

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 failures. ConfigProvider selects the source.
- In rat-stack, declare environment inputs in `.env.schema`. Alchemy provider credentials come from profiles, not environment variables.
- Do not unwrap a redacted value for logs or public examples.

See also: [services](/lore/services-capture-dependencies), [Layer composition](/lore/layers-make-dependencies-explicit), [failures](/lore/error-model), and [tests](/lore/tests-that-earn-their-place).

## Sources

1. [Effect contributors. 2026. Config. Effect 4.0.0.](https://github.com/Effect-TS/effect/blob/67ba4e46a11ccda0b6761578bfd22c04ae00167d/packages/effect/src/Config.ts)
   Effect-TS. Config.Literals, defaults, schema validation, and capitalized Config constructors. Accessed 2026-10-06.

2. [Effect contributors. 2026. ConfigProvider. Effect 4.0.0.](https://github.com/Effect-TS/effect/blob/67ba4e46a11ccda0b6761578bfd22c04ae00167d/packages/effect/src/ConfigProvider.ts)
   Effect-TS. Providers replace the config source; fromUnknown and layer support controlled inputs. Accessed 2026-10-06.

3. [rat-stack contributors. 2026. ConfigService.](https://github.com/joelhooks/rat-stack/blob/65e9465f38092e24486392f22c08f45d61230c20/packages/core/src/config-service.ts)
   rat-stack. The factory provides a parsing Layer and a typed configLayer that bypasses parsing for controlled tests. Accessed 2026-10-06.

4. [rat-stack contributors. 2026. AppConfig tests.](https://github.com/joelhooks/rat-stack/blob/65e9465f38092e24486392f22c08f45d61230c20/packages/core/test/app-config.test.ts)
   rat-stack. Tests cover supplied config, a missing-value default, an invalid value, and direct typed configuration. Accessed 2026-10-06.

5. [Langton, Kit. 2026. Config. Effect Solutions.](https://github.com/kitlangton/effect-solutions/blob/09f82e6c5c928e7232cd32daf04d7c6a830b63f7/packages/website/docs/07-config.md)
   Kit Langton. Topic framing for config Layers and replaceable providers; lowercase constructor examples do not match Effect 4.0.0. Accessed 2026-10-06.

## Lore on this page

- [Handle expected failures without hiding defects](/lore/error-model)

## Linked from

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Effect basics → An Effect describes work, expected failures, and required services before a runtime executes it. → [Read page](https://ratstack.sh/lore/effect-basics)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- Rat Stack lore | rat-stack → Short, source-grounded notes on the ideas and decisions behind rat-stack. → [Read page](https://ratstack.sh/lore)

- Source change history (log.md) → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)

## Unlinked mentions

- [Agent rules for rat-stack (AGENTS.md)](https://ratstack.sh/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.
