Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Config

Descriptions of configuration values that can be read from a ConfigProvider. A Config<T> explains which keys to read, how to decode and validate them, and how to combine defaults, fallbacks, nested paths, and multiple settings. Configs are also Effects, so they can be yielded in Effect.gen after a provider has been supplied.

34 exports Since v2.0.0 Source

Combinators

Since v2.0.0

Combines multiple configs into a single config that parses all of them.

When to use

Use when you need to group related configs into a tuple or named struct.

Details

Accepts a tuple (preserves positions), an iterable, or a record of configs. Returns a config whose parsed value mirrors the input shape.

A combined config is absent when any child is absent and no child fails. Validation and source errors propagate even when another child is absent. An outer withDefault replaces the entire absent group, while option returns None. Apply defaults to individual children to preserve the values of other children.

Unlike a Schema.Struct passed to schema, all combines independent lookups. A struct validates an existing object and fails when required fields are missing; all can recover missing children through a group default.

Signature

declare function all<Arg extends Iterable<Config<any>, any, any> | Record<string, Config<any>>>(arg: Arg): Config<[Arg] extends [readonly Array<Config<any>>] ? { [K in string | number | symbol]: [Arg[K]] extends [Config<A>] ? A : never } : [Arg] extends [Iterable<Config<A>, any, any>] ? Array<A> : [Arg] extends [Record<string, Config<any>>] ? { [K in string | number | symbol]: [Arg[K]] extends [Config<A>] ? A : never } : never>

Example Defaulting an incomplete config group

import { Config, ConfigProvider, Effect } from "effect"
const dbConfig = Config.all({
host: Config.String("host"),
port: Config.Number("port")
}).pipe(Config.withDefault({ host: "localhost", port: 5432 }))
const provider = ConfigProvider.fromUnknown({ host: "db.internal", port: 6000 })
await Effect.runPromise(dbConfig.parse(provider)) // => { host: "db.internal", port: 6000 }
const missingPort = ConfigProvider.fromUnknown({ host: "db.internal" })
await Effect.runPromise(dbConfig.parse(missingPort)) // => { host: "localhost", port: 5432 }
Since v2.0.0

Scopes a config under a named prefix.

When to use

Use when you need to group related config keys under a common namespace.

Details

The prefix is prepended to every key the inner config reads. With fromUnknown this means an extra object level; with fromEnv it means a _-separated prefix on env var names.

Multiple nested calls compose: the outermost name becomes the outermost path segment.

See

  • all โ€“ combine multiple configs into a struct
  • schema โ€“ read structured config from a schema

Signature

declare const nested: {
(name: string): <A>(self: Config<A>) => Config<A>;
<A>(self: Config<A>, name: string): Config<A>;
}

Example

import { Config, ConfigProvider, Effect } from "effect"
const dbConfig = Config.all({
host: Config.String("host"),
port: Config.Number("port")
}).pipe(Config.nested("database"))
const provider = ConfigProvider.fromUnknown({
database: { host: "localhost", port: "5432" }
})
Effect.runSync(dbConfig.parse(provider)) // => { host: "localhost", port: 5432 }

Example Reading env vars with a nested prefix

import { Config, ConfigProvider, Effect } from "effect"
const host = Config.String("host").pipe(Config.nested("database"))
const provider = ConfigProvider.fromEnv({
env: { database_host: "localhost" }
})
Effect.runSync(host.parse(provider)) // => "localhost"
Since v2.0.0

Makes a config optional: returns Some(value) on success and None when the config is absent.

When to use

Use when you need to handle a config key that may or may not be present.

Gotchas

Validation and source errors still propagate. For an all group, any absent child produces None unless another child fails. Successful values are always wrapped in Some, including undefined when the schema explicitly accepts it. Schema configs first represent a missing or incompatible provider shape as undefined; None is returned only when the schema rejects that value and no relevant input was found.

See

  • withDefault โ€“ provide a concrete fallback value instead

Signature

declare function option<A>(self: Config<A>): Config<Option<A>>

Example Reading optional config

import { Config, ConfigProvider, Effect, Option } from "effect"
const maybePort = Config.option(Config.Number("port"))
const provider = ConfigProvider.fromUnknown({})
Effect.runSync(maybePort.parse(provider)) // => Option.none()
Since v2.0.0

Provides a fallback config when parsing fails with a ConfigError.

When to use

Use when you need to try an alternative config source after the primary one fails.

Details

Unlike withDefault, this handles both semantic absence and all ConfigErrors. The fallback function receives the error and returns a new Config.

Gotchas

The fallback's result replaces the original failure. If the fallback is absent, an outer withDefault or option can recover it. If the fallback fails, only its error propagates. Defects and interruptions never reach the fallback; they propagate unchanged.

See

  • withDefault โ€“ fallback only on semantic absence

Signature

declare const orElse: {
<A2>(that: (error: ConfigError) => Config<A2>): <A>(self: Config<A>) => Config<A2 | A>;
<A, A2>(self: Config<A>, that: (error: ConfigError) => Config<A2>): Config<A | A2>;
}

Example Trying another port before using a default

import { Config, ConfigProvider, Effect } from "effect"
const port = Config.Int("PORT").pipe(
Config.orElse(() => Config.Int("BACKUP_PORT")),
Config.withDefault(3000)
)
const provider = ConfigProvider.fromUnknown({ PORT: "invalid", BACKUP_PORT: "8080" })
await Effect.runPromise(port.parse(provider)) // => 8080
const missingBackup = ConfigProvider.fromUnknown({ PORT: "invalid" })
await Effect.runPromise(port.parse(missingBackup)) // => 3000

Provides a fallback value when the config is absent.

When to use

Use when you need to make a config key optional with a sensible default.

Gotchas

Validation and source errors still propagate. For an all group, any absent child causes the default to replace the entire group unless another child fails. Apply defaults to individual children to preserve other values.

A schema that successfully decodes absent input keeps its decoded value instead of using the default. Schema configs first represent a missing or incompatible provider shape as undefined; the default is used only when the schema rejects that value and no relevant input was found.

See

  • option โ€“ returns Option instead of a default value
  • orElse โ€“ catches all errors, not just absent input

Signature

declare const withDefault: {
<A2>(defaultValue: A2): <A>(self: Config<A>) => Config<A2 | A>;
<A, A2>(self: Config<A>, defaultValue: A2): Config<A | A2>;
}

Example Defaulting a missing port

import { Config, ConfigProvider, Effect } from "effect"
const port = Config.Number("port").pipe(Config.withDefault(3000))
const provider = ConfigProvider.fromUnknown({})
Effect.runSync(port.parse(provider)) // => 3000

Constructors

Since v4.0.0

Creates a config for array values that may also be read from a separated string.

When to use

Use when you need to read either structural array input or a flat value such as "otlp,console" from an environment variable.

Details

Pass a string or ConfigProvider.Path as the second argument to set the lookup path. When no path is needed, pass the options object directly. The separator defaults to ",".

See

  • Record for key-value input from structural records or separated strings.

Signature

declare function Array<V extends ConstraintCodec<unknown, unknown, never, never>>(value: V, options?: ArrayOptions): Config<readonly Array<V["Type"]>>
declare function Array<V extends ConstraintCodec<unknown, unknown, never, never>>(value: V, path: string | Path, options?: ArrayOptions): Config<readonly Array<V["Type"]>>

Example Reading a comma-separated array

import { Config, ConfigProvider, Effect, Schema } from "effect"
const config = Config.Array(Schema.String, "EXPORTERS")
const provider = ConfigProvider.fromEnv({ env: { EXPORTERS: "otlp,console" } })
Effect.runSync(config.parse(provider)) // => ["otlp", "console"]
Since v2.0.0

Creates a config for a boolean value parsed from common string representations.

When to use

Use to read boolean flags from string-like config sources.

Details

Accepted values: true, false, yes, no, on, off, 1, 0, y, n.

Signature

declare function Boolean(name?: string): Config<boolean>

Example Reading a boolean flag

import { Config, ConfigProvider, Effect } from "effect"
const program = Config.Boolean("FEATURE_FLAG")
const provider = ConfigProvider.fromEnv({
env: {
FEATURE_FLAG: "yes"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => true

ByteSize

unstable
Since v4.0.0

Creates a config for an exact, human-readable byte-size value.

Details

Decimal symbols such as kB use powers of 1,000, while binary symbols such as KiB use powers of 1,024.

Signature

declare function ByteSize(name?: string): Config<ByteSize>
Since v2.0.0

Creates a config for a Date value parsed from a string.

When to use

Use to read date settings that must parse to valid Date values.

Details

Shortcut for Config.schema(Schema.Date, name).

Gotchas

Fails with a SchemaError if the string produces an invalid Date.

Signature

declare function Date(name?: string): Config<Date>

Example Reading a date

import { Config, ConfigProvider, Effect } from "effect"
const createdAt = Config.Date("CREATED_AT")
const provider = ConfigProvider.fromUnknown({ CREATED_AT: "2024-01-15" })
Effect.runSync(createdAt.parse(provider)).toISOString() // => "2024-01-15T00:00:00.000Z"
Since v2.5.0

Creates a config for a Duration value parsed from a human-readable string.

When to use

Use to read time duration settings such as timeouts, intervals, or TTLs.

Details

Shortcut for Config.schema(Schema.DurationFromString, name).

Accepts any string that Duration.fromInput can parse (e.g. "10 seconds", "500 millis", "Infinity", "-Infinity").

See

  • schema for decoding configuration values with a custom codec

Signature

declare function Duration(name?: string): Config<Duration>

Example Reading a duration

import { Config, ConfigProvider, Duration, Effect } from "effect"
const program = Config.Duration("DURATION").pipe(Effect.map(Duration.toMillis))
const provider = ConfigProvider.fromEnv({
env: {
DURATION: "10 seconds"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => 10000
Since v2.0.0

Creates a config that always fails with the given error.

When to use

Use when you need to re-raise a specific config error, such as inside orElse.

Signature

declare function fail(err: SchemaError | SourceError): Config<never>
Since v4.0.0

Creates a config for a finite number (rejects NaN and Infinity).

When to use

Use to read a numeric config value that must be finite.

Details

Shortcut for Config.schema(Schema.Finite, name).

See

  • Number for accepting NaN and Infinity
  • Int for accepting only integers

Signature

declare function Finite(name?: string): Config<number>
Since v4.0.0

Creates a config for an integer value. Rejects floats.

When to use

Use to read a numeric config value that must be an integer.

Details

Shortcut for Config.schema(Schema.Int, name).

See

  • Number for accepting any number
  • Port for accepting only integers in 1 through 65535

Signature

declare function Int(name?: string): Config<number>
Since v2.0.0

Creates a config that only accepts a specific literal value.

When to use

Use to restrict a config to a single, specific literal value.

Details

Shortcut for Config.schema(Schema.Literal(literal), name).

See

  • Literals โ€“ accepts multiple literal values

Signature

declare function Literal<L extends LiteralValue>(literal: L, name?: string): Config<L>

Example Restricting to a literal

import { Config, ConfigProvider, Effect } from "effect"
const env = Config.Literal("production", "ENV")
const provider = ConfigProvider.fromUnknown({ ENV: "production" })
Effect.runSync(env.parse(provider)) // => "production"
Since v4.0.0

Creates a config that only accepts one of the specified literal values.

When to use

Use to restrict a config to a fixed set of allowed literal values.

Details

Shortcut for Config.schema(Schema.Literals(literals), name).

See

  • Literal for accepting one specific literal value

Signature

declare function Literals<L extends readonly Array<LiteralValue>>(literals: L, name?: string): Config<L[number]>

Example Restricting to a set of literals

import { Config, ConfigProvider, Effect } from "effect"
const env = Config.Literals(["development", "production"], "ENV")
const provider = ConfigProvider.fromUnknown({ ENV: "development" })
Effect.runSync(env.parse(provider)) // => "development"
Since v2.0.0

Creates a config for a log level string.

When to use

Use to read Effect log-level settings from configuration.

Details

Accepted values: "All", "Fatal", "Error", "Warn", "Info", "Debug", "Trace", "None".

Signature

declare function LogLevel(name?: string): Config<LogLevel>

Example Reading a log level

import { Config, ConfigProvider, Effect } from "effect"
const program = Config.LogLevel("LOG_LEVEL")
const provider = ConfigProvider.fromEnv({
env: {
LOG_LEVEL: "Info"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => "Info"

Creates a config for a non-empty string value. Fails if the value is an empty string.

When to use

Use to read a string config value that must contain at least one character.

Details

Shortcut for Config.schema(Schema.NonEmptyString, name).

See

  • String for allowing empty strings

Signature

declare function NonEmptyString(name?: string): Config<string>
Since v2.0.0

Creates a config for a numeric value (including NaN, Infinity).

When to use

Use when you need config input to accept JavaScript's full number domain, including NaN and infinities, rather than reject non-finite values.

Details

Shortcut for Config.schema(Schema.Number, name).

See

  • Finite for rejecting NaN and Infinity
  • Int for accepting only integers

Signature

declare function Number(name?: string): Config<number>
Since v3.16.0

Creates a config for a port number (integer in 1โ€“65535).

When to use

Use to read network port settings that must be valid port numbers.

Details

Accepts integers from 1 through 65535.

See

  • Int for integer config values outside the port range

Signature

declare function Port(name?: string): Config<number>

Example Reading a port

import { Config, ConfigProvider, Effect } from "effect"
const program = Config.Port("PORT")
const provider = ConfigProvider.fromEnv({
env: {
PORT: "8080"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => 8080
Since v4.0.0

Creates a config for record values that may also be read from a separated key-value string.

When to use

Use when you need to read either structural record input or a flat value such as "service.name=my-service,service.version=1.0.0" from an environment variable.

Details

Pass a string or ConfigProvider.Path as the third argument to set the lookup path. When no path is needed, pass the options object directly. The separator defaults to "," and keyValueSeparator defaults to "=".

See

  • Array for array input from structural arrays or separated strings.

Signature

declare function Record<K extends Key & ConstraintCodec<unknown, unknown, never, never>, V extends ConstraintCodec<unknown, unknown, never, never>>(key: K, value: V, options?: RecordOptions): Config<Type<K, V>>
declare function Record<K extends Key & ConstraintCodec<unknown, unknown, never, never>, V extends ConstraintCodec<unknown, unknown, never, never>>(key: K, value: V, path: string | Path, options?: RecordOptions): Config<Type<K, V>>

Example Reading a comma-separated record

import { Config, ConfigProvider, Effect, Schema } from "effect"
const config = Config.Record(Schema.String, Schema.String, "OTEL_RESOURCE_ATTRIBUTES")
const provider = ConfigProvider.fromEnv({
env: {
OTEL_RESOURCE_ATTRIBUTES:
"service.name=my-service,service.version=1.0.0,custom.attribute=value"
}
})
const result = Effect.runSync(config.parse(provider))
result["service.name"] // => "my-service"
result["service.version"] // => "1.0.0"
result["custom.attribute"] // => "value"
Since v2.0.0

Creates a config for a redacted string value. The parsed result is wrapped in a Redacted container that hides the value from logs and toString.

When to use

Use to read secret string settings that should not be exposed in logs or string output.

Details

Shortcut for Config.schema(Schema.Redacted(Schema.String), name).

See

  • String for non-secret string settings

Signature

declare function Redacted(name?: string): Config<Redacted<string>>

Example Reading a secret

import { Config, ConfigProvider, Effect } from "effect"
const program = Config.Redacted("API_KEY").pipe(Effect.map(String))
const provider = ConfigProvider.fromEnv({
env: {
API_KEY: "sk-1234567890abcdef"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => "<redacted>"
Since v2.0.0

Creates a config for a single string value.

When to use

Use when reading a single string env var or config key.

Details

Shortcut for Config.schema(Schema.String, name).

See

Signature

declare function String(name?: string): Config<string>

Example Reading a string config

import { Config, ConfigProvider, Effect } from "effect"
const host = Config.String("HOST")
const provider = ConfigProvider.fromUnknown({ HOST: "localhost" })
Effect.runSync(host.parse(provider)) // => "localhost"
Since v2.0.0

Creates a config that always succeeds with the given value, ignoring the provider entirely.

When to use

Use when you need a hardcoded config value, such as inside orElse or tests.

Signature

declare function succeed<T>(value: T): Config<T>

Example Returning a constant fallback

import { Config, ConfigProvider, Effect } from "effect"
const host = Config.String("HOST").pipe(
Config.orElse(() => Config.succeed("localhost"))
)
const provider = ConfigProvider.fromUnknown({})
Effect.runSync(host.parse(provider)) // => "localhost"
Since v3.11.0

Creates a config for a URL value parsed from a string.

When to use

Use to read configuration values that must be valid URL strings.

Details

This is a shortcut for Config.schema(Schema.URL, name).

Gotchas

Fails if the string cannot be parsed by the URL constructor.

See

  • schema for decoding configuration values with a custom codec

Signature

declare function URL(name?: string): Config<URL>

Example Reading a URL

import { Config, ConfigProvider, Effect } from "effect"
const program = Config.URL("URL").pipe(Effect.map((url) => url.href))
const provider = ConfigProvider.fromEnv({
env: {
URL: "https://example.com"
}
})
Effect.runSync(
program.pipe(Effect.provideService(ConfigProvider.ConfigProvider, provider))
) // => "https://example.com/"

Converting

Since v2.0.0

Constructs a Config<T> from a value matching Wrap<T>.

When to use

Use when accepting config from callers who may pass either a single Config or a record of individual Configs.

Details

If the input is already a Config, it is returned as-is. Otherwise, each key is recursively unwrapped and combined.

See

  • Wrap โ€“ the utility type accepted by this function

Signature

declare function unwrap<T>(wrapped: Wrap<T>): Config<T>

Example Unwrapping a record of configs

import { Config, ConfigProvider, Effect } from "effect"
interface Options {
key: string
}
const makeConfig = (config: Config.Wrap<Options>): Config.Config<Options> =>
Config.unwrap(config)
const config = makeConfig({ key: Config.String("key") })
const provider = ConfigProvider.fromUnknown({ key: "value" })
Effect.runSync(config.parse(provider)) // => { key: "value" }

Errors

Represents the error type produced when config loading or validation fails.

When to use

Use when you need to inspect config loading or validation failures.

Details

Wraps either:

  • A SourceError โ€” the provider could not read data (I/O failure).
  • A SchemaError โ€” the data was found but did not match the schema (wrong type, out of range, missing key, etc.).

See

  • orElse โ€“ recover from a ConfigError
  • withDefault โ€“ provide a fallback when relevant input is absent

Signature

declare class ConfigError {
constructor(cause: SchemaError | SourceError);
readonly _tag: "ConfigError";
readonly cause: SchemaError | SourceError;
readonly name: string;
message: string;
toString(): string;
}

Guards

Since v2.0.0

Returns true if u is a Config instance.

When to use

Use when you need to distinguish a Config from an unknown value before calling .parse or unwrap.

Signature

declare function isConfig(u: unknown): u is Config<unknown>

Example Checking Config values

import { Config } from "effect"
Config.isConfig(Config.String("HOST")) // => true
Config.isConfig("not a config") // => false

Mapping

Since v4.0.0

Lets you sequence multiple configs that depend on each other or branch to multiple different configs depending on the parent.

When to use

Use when you want to maintain 2 sets of env vars with different names, and switch between whole sets based on a single dedicated env var. Or when you want to provide a variety of environment variable names (PORT, BACKEND_PORT, API_PORT) in order of preference for a specific configuration option, such as the listening port.

Signature

declare const flatMap: {
<A, B>(f: (a: A) => Config<B>): (self: Config<A>) => Config<B>;
<A, B>(self: Config<A>, f: (a: A) => Config<B>): Config<B>;
}

Example fallback configs and branching

import { Config, Option } from "effect"
const EnvVar = (name: string) =>
Config.Literals([
...["prod", "production", "PROD", "PRODUCTION"] as const,
...["dev", "development", "DEV", "DEVELOPMENT"] as const
], name)
const withAbsenceFallback = <A, B>(fallback: Config.Config<A>) => (self: Config.Config<B>): Config.Config<A | B> =>
Config.flatMap(
Config.option(self),
Option.match({
onNone: () => fallback,
onSome: Config.succeed<A | B>
})
)
// const ENV: Config.Config<"dev" | "prod">
const ENV = EnvVar("ENV").pipe(
withAbsenceFallback(EnvVar("NODE_ENV")),
Config.map((fuzzyEnv) =>
fuzzyEnv.toLowerCase().startsWith("dev") ? "dev" : "prod"),
Config.withDefault('dev')
)
// const hostConfig: Config.Config<string>
const hostConfig = ENV.pipe(
Config.flatMap((env) =>
env === "dev"
// dev is very forgiving
? Config.NonEmptyString("DEV_HOST").pipe(
Config.orElse(() => Config.NonEmptyString("HOST")),
Config.orElse(() => Config.succeed("localhost"))
)
// prod is much stricter
: Config.NonEmptyString("PROD_HOST").pipe(
withAbsenceFallback(Config.NonEmptyString("HOST"))
)
)
)
Since v2.0.0

Transforms the parsed value of a config with a pure function.

When to use

Use when you need to transform a parsed config value with a function that cannot fail.

See

  • mapEffect โ€“ when the transformation can fail

Signature

declare const map: {
<A, B>(f: (a: A) => B): (self: Config<A>) => Config<B>;
<A, B>(self: Config<A>, f: (a: A) => B): Config<B>;
}

Example Uppercasing a string config

import { Config, ConfigProvider, Effect } from "effect"
const upper = Config.String("name").pipe(
Config.map((s) => s.toUpperCase())
)
const provider = ConfigProvider.fromUnknown({ name: "alice" })
Effect.runSync(upper.parse(provider)) // => "ALICE"

Transforms the parsed value with a function that may fail.

When to use

Use when you need to transform a parsed config value with a function that can produce a ConfigError (e.g. parsing a URL, checking a range).

See

  • map โ€“ when the transformation cannot fail

Signature

declare const mapEffect: {
<A, B>(f: (a: A) => Effect<B, ConfigError>): (self: Config<A>) => Config<B>;
<A, B>(self: Config<A>, f: (a: A) => Effect<B, ConfigError>): Config<B>;
}

Example Wrapping a value in an effectful transformation

import { Config, ConfigProvider, Effect } from "effect"
const trimmed = Config.String("name").pipe(
Config.mapEffect((s) => Effect.succeed(s.trim()))
)
const provider = ConfigProvider.fromUnknown({ name: " Alice " })
Effect.runSync(trimmed.parse(provider)) // => "Alice"

Models

Config

interface
Since v2.0.0

A recipe for extracting a typed value T from a ConfigProvider.

When to use

Use to describe typed configuration that can be parsed from a provider or yielded inside Effect.gen.

Details

Key members:

  • parse(provider) โ€“ runs the config against a specific provider.
  • Yieldable โ€“ can be yielded inside Effect.gen, which automatically resolves the current ConfigProvider from the context.
  • Pipeable โ€“ supports .pipe(Config.map(...)) etc.

See

  • schema โ€“ the main way to create a Config

Signature

interface Config<out T> extends Effect<T, ConfigError> {
readonly "~effect/Config": "~effect/Config";
readonly parse: (provider: ConfigProvider) => Effect<T, ConfigError>;
}

Schemas

Since v4.0.0

Creates a Config<T> from a Schema.Codec.

When to use

Use when you need to read structured or schema-validated configuration.

Details

The optional path sets the local path segment(s) for the config lookup. It is appended to the logical path prefix accumulated from outer nested calls. Pass a single string for a flat key or an array for nested paths.

Convenience constructors such as String, Number, and Boolean delegate to this API.

The codec is converted to its canonical StringTree form. Its encoded shape determines how provider data is loaded: scalar schemas read a co-located scalar value, object schemas read declared properties and matching record keys, and array schemas read indexed children. A mixed-shape union loads each member according to that member's shape before applying the union's mode and checks.

At the config's lookup path, a missing node or a node that cannot provide the representation required by the schema is decoded as undefined. Missing object properties remain omitted so the schema's property semantics still apply. Decoding success always wins, even when no provider input was found. For example, Schema.UndefinedOr(Schema.String) decodes to undefined and is not replaced by withDefault. If decoding fails and no relevant representation was found, the config is absent. Invalid data in a relevant representation is a validation failure. Provider SourceErrors are always failures.

Gotchas

Plain Schema.Array and Schema.Record schemas use structural provider input. Use Array or Record when a flat separated string must also be accepted.

Schema.Struct and all describe different lookup models. An existing object, even an empty one, is validated as a whole by a struct; missing required fields cause a validation failure. An all group combines independent lookups and is absent if any child is absent and none fail.

The canonical StringTree encoding must expose a concrete scalar, object, array, or union shape. Opaque encodings such as Schema.Any, Schema.Unknown, Schema.ObjectKeyword, Schema.Json, and Schema.MutableJson are rejected synchronously when this config is constructed, including when they are nested in another schema. Suspended recursive schemas remain supported when their eventual shape is concrete. Declarations such as Schema.URL also remain supported when their canonical encoding has a concrete shape. To read arbitrary JSON from one scalar value, use Schema.fromJsonString(Schema.Json).

See

Signature

declare function schema<T>(codec: ConstraintCodec<T, unknown>, path?: string | Path): Config<T>

Example Reading a structured config

import { Config, ConfigProvider, Effect, Schema } from "effect"
const DbConfig = Config.schema(
Schema.Struct({
host: Schema.String,
port: Schema.Int
}),
"db"
)
const provider = ConfigProvider.fromUnknown({
db: { host: "localhost", port: 5432 }
})
Effect.runSync(DbConfig.parse(provider)) // => { host: "localhost", port: 5432 }

Utility Types

Since v2.5.0

Extracts the successfully parsed value type from a Config.

When to use

Use to derive the parsed value type from an existing Config value when declaring reusable config-driven types.

See

  • Config for the config type whose parsed value is extracted
  • Effect.Success for extracting the success type from any Effect

Signature

type Success<T> = [T] extends [Config<infer A>] ? A : never

Wrap

type
Since v2.0.0

Utility type that recursively replaces primitives with Config in a nested structure.

When to use

Use when typing the input of unwrap so callers can pass either a Config or a record of Configs.

Details

Config.Wrap<{ key: string }> becomes { key: Config<string> } | Config<{ key: string }>

See

  • unwrap โ€“ construct a Config from a Wrap<T>

Signature

type Wrap<A> = [NonNullable<A>] extends [infer T] ? [IsPlainObject<T>] extends [true] ? { [K in keyof A]: Wrap<A[K]> } | Config<A> : Config<A> : Config<A>