Schema Helpers
Defaults, optionality, redaction, JSON parsing, and variable sources.
withDefault
Uses a decoded default when the runtime value is absent:
values: {
PORT: port.pipe(withDefault(3000)),
}
The data-first form is also supported:
values: {
PORT: withDefault(port, 3000),
}
The output type does not include undefined.
optional
Allows a missing value and includes undefined in the output type:
values: {
TRACE_ENDPOINT: optional(url),
}
redacted
Wraps decoded values with Effect Redacted:
import { Effect, Redacted } from "effect";
const appEnv = createEnv(
server(
{
API_SECRET: redacted(requiredString),
},
{
runtimeEnv: { API_SECRET: "secret" },
},
),
);
const env = Effect.runSync(appEnv.server);
const secret = Redacted.value(env.API_SECRET);
Redacted schemas are server-only. Resolver-backed schemas are redacted automatically and do not need this helper.
json
Parses a JSON string and validates the parsed value:
import { Schema } from "effect";
values: {
FEATURE_FLAGS: json(
Schema.Struct({
darkMode: Schema.Boolean,
newUI: Schema.Boolean,
}),
),
}
fromEnv
Maps one property to an exact runtime environment name:
values: {
POSTHOG_API_KEY: optional(requiredString).pipe(
fromEnv("PUBLIC_POSTHOG_API_KEY"),
),
}
Use the fragment’s prefix when every variable follows the same naming
convention. Use fromEnv for exceptions.
fromResolver
Makes one configured resolver the authoritative source:
values: {
STRIPE_API_KEY: requiredString.pipe(
fromResolver(aws, "production/stripe#api-key"),
),
}
Source combinators are terminal variable definitions. TypeScript rejects later
schema combinators and a second fromEnv or fromResolver, so source metadata
cannot disappear during composition.
fromEnv and fromResolver do not change schema decoding. They describe
where the unknown input comes from when the Effect runs.