SchemaTransformation
Builds two-way conversions used by schemas.
A Transformation<T, E> describes how to decode an encoded value into a
decoded value and how to encode it back again. Schema APIs use
transformations to connect two representations, such as a string and a
number, a JSON value and a richer TypeScript value, or a form field and an
application value. This module includes transformation and middleware types,
constructors for pure or effectful conversions, and common conversions used
by the Schema module.
Constructors
Constructs a Transformation from an object with decode and encode
Getters. If the input is already a Transformation, returns it as-is.
When to use
Use when you already have schema getter instances and want to pair them into a schema transformation.
- You want idempotent wrapping (won't double-wrap).
Details
- Returns the input unchanged if it is already a
Transformation.
See
- transform — simpler constructor from pure functions
- transformOrFail — constructor from effectful functions
- Transformation
Signature
declare function make<T, E, RD = never, RE = never>(options: { readonly decode: Getter<T, E, RD>; readonly encode: Getter<E, T, RE>;}): Transformation<T, E, RD, RE>Example
(Wrapping existing getters)
import { SchemaGetter, SchemaTransformation } from "effect"
const t = SchemaTransformation.make({ decode: SchemaGetter.transform<number, string>((s) => Number(s)), encode: SchemaGetter.transform<string, number>((n) => String(n))})t._tag // => "Transformation"passthrough
Transforms values by returning the input unchanged in both directions.
When to use
Use when you need a schema transformation to connect two schemas that share the same type with no actual conversion.
Details
- Both decode and encode are no-ops.
- Returns a shared singleton instance (no allocation per call).
- By default,
TandEmust be the same type. Pass{ strict: false }to bypass the type constraint.
See
Signature
declare function passthrough<T, E>(options: { readonly strict: false;}): Transformation<T, E>declare function passthrough<T>(): Transformation<T, T>Example
(Chaining schemas with no conversion)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.Trim.pipe( Schema.decodeTo(Schema.FiniteFromString, SchemaTransformation.passthrough()))Schema.decodeSync(schema)("1") // => 1passthroughSubtype
Transforms values without changing them, typed so that E extends T — the encoded
type is a subtype of the decoded type.
When to use
Use when you need a no-op schema transformation whose encoded side is more specific than its decoded side.
Details
- Both decode and encode are no-ops (same as passthrough).
- Returns a shared singleton instance.
See
Signature
declare function passthroughSubtype<T, E>(): Transformation<T, E>Example
(Passing through subtypes)
import { SchemaTransformation } from "effect"
const t: SchemaTransformation.Transformation<string, "a" | "b"> = SchemaTransformation.passthroughSubtype<string, "a" | "b">()passthroughSupertype
Transforms values without changing them, typed so that T extends E, where the decoded
type T is a subtype of the encoded type E.
When to use
Use when you need a no-op schema transformation whose decoded side is narrower than the encoded side.
Details
Both decode and encode are no-ops and return a shared singleton transformation.
See
Signature
declare function passthroughSupertype<T, E>(): Transformation<T, E>Example
(Passing through supertypes)
import { SchemaTransformation } from "effect"
const t: SchemaTransformation.Transformation<"a" | "b", string> = SchemaTransformation.passthroughSupertype<"a" | "b", string>()Converting
bigintFromString
Decodes a string into a bigint and encodes a bigint back to a
string.
When to use
Use when you need a schema transformation to parse large integer strings (e.g. database IDs, blockchain values).
Details
Decoding coerces the string to a bigint like BigInt(s). Encoding coerces
the bigint to a string like String(n). Decoding fails if the string is not
a valid bigint representation.
See
Signature
declare const bigintFromString: Transformation<bigint, string, never, never>Example
(Converting a string to a BigInt)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.BigInt, SchemaTransformation.bigintFromString))Schema.decodeSync(schema)("42") // => 42ndateFromMillis
Decodes epoch milliseconds into a Date and encodes a Date back to epoch
milliseconds.
When to use
Use when you need a schema transformation for numeric timestamps represented as milliseconds since the Unix epoch.
Details
Decoding creates a Date from the number like new Date(ms). Encoding
returns the Date timestamp like date.getTime().
Gotchas
This transformation does not validate date validity. NaN, Infinity, and
-Infinity decode to invalid Date instances.
See
Signature
declare const dateFromMillis: Transformation<globalThis.Date, number>Example
(Converting milliseconds to a Date)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.Number.pipe( Schema.decodeTo(Schema.Date, SchemaTransformation.dateFromMillis))Schema.decodeSync(schema)(0).toISOString() // => "1970-01-01T00:00:00.000Z"dateFromString
Decodes a string into a Date and encodes a Date back to a string.
When to use
Use when you need a schema transformation to parse date strings from APIs or user input.
Details
Decoding creates a Date from the string like new Date(s). Encoding
converts the Date to an ISO string like date.toISOString(), returning
"Invalid Date" for invalid dates.
See
Signature
declare const dateFromString: Transformation<globalThis.Date, string>Example
(Converting a string to a Date)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.Date, SchemaTransformation.dateFromString))Schema.decodeSync(schema)("2024-01-01").toISOString() // => "2024-01-01T00:00:00.000Z"numberFromString
Decodes a string into a number and encodes a number back to a
string.
When to use
Use when you need a schema transformation to parse numeric strings from APIs, form data, or URL parameters.
Details
Decoding coerces the string to a number like Number(s). Encoding coerces
the number to a string like String(n). This does not validate that the
result is finite; combine with Schema.Finite or Schema.Int for stricter
checks.
See
Signature
declare const numberFromString: Transformation<number, string, never, never>Example
(Converting a string to a number)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.Number, SchemaTransformation.numberFromString))Schema.decodeSync(schema)("42") // => 42Decoding
fromFormData
Decodes a FormData instance into a nested record using bracket-path keys and
encodes object-like values back into FormData.
When to use
Use when you need a schema transformation for form or multipart payloads
whose keys, such as user[name] or items[0], should become nested data.
Details
Decode preserves string and Blob leaves. Encode flattens nested objects and
arrays into bracket-path entries and returns an empty FormData for
non-object inputs.
See
Signature
declare const fromFormData: Transformation<unknown, FormData, never, never>Example
(Decoding FormData)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.instanceOf(FormData).pipe( Schema.decodeTo(Schema.Unknown, SchemaTransformation.fromFormData))const formData = new FormData()formData.append("user[name]", "Alice")Schema.decodeSync(schema)(formData) // => { user: { name: "Alice" } }fromJsonString
Decodes a JSON string with JSON.parse and encodes a value with
JSON.stringify.
When to use
Use when you need a schema transformation to decode JSON stored or transmitted as a string, usually before composing with another schema that validates the parsed structure.
Details
The reviver option is passed to JSON.parse during decoding. The
replacer and space options are passed to JSON.stringify during
encoding. Decode fails with InvalidValue for invalid JSON, and encode can
fail with InvalidValue when JSON.stringify cannot serialize the value.
See
Signature
declare function fromJsonString(options?: { readonly replacer?: JsonReplacer; readonly reviver?: (this: any, key: string, value: any) => any; readonly space?: string | number;}): Transformation<unknown, string>Example
(Parsing JSON)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.Unknown, SchemaTransformation.fromJsonString()))Schema.decodeSync(schema)("{\"ok\":true}") // => { ok: true }fromURLSearchParams
Decodes URLSearchParams into a nested record using bracket-path keys and
encodes object-like values back into URLSearchParams.
When to use
Use when you need a schema transformation for query strings whose keys, such
as filter[name] or items[0], should become nested data.
Details
Decode produces string leaves. Encode flattens nested objects and arrays into
bracket-path entries and returns empty URLSearchParams for non-object
inputs.
See
Signature
declare const fromURLSearchParams: Transformation<unknown, URLSearchParams, never, never>Example
(Decoding URLSearchParams)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.instanceOf(URLSearchParams).pipe( Schema.decodeTo(Schema.Unknown, SchemaTransformation.fromURLSearchParams))Schema.decodeSync(schema)(new URLSearchParams("user[name]=Alice")) // => { user: { name: "Alice" } }Encoding
stringFromBase64String
Decodes a Base64-encoded string into a UTF-8 string and encodes a
UTF-8 string back to a Base64 string.
When to use
Use when you need a schema transformation for text data transmitted as Base64 strings.
Details
Decoding parses the Base64 string into a UTF-8 string. Encoding writes the string as a Base64 string.
See
- uint8ArrayFromBase64String
Schema.StringFromBase64- a ready-made schema wrapping this transformation.
Signature
declare const stringFromBase64String: Transformation<string, string>Example
(Converting Base64 to a string)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.String, SchemaTransformation.stringFromBase64String))Schema.decodeSync(schema)("aGVsbG8=") // => "hello"stringFromBase64UrlString
Decodes a base64 (URL) encoded string into a UTF-8 string and encodes it back.
When to use
Use when you need a schema transformation for text data transmitted as Base64 URL-safe strings.
Details
Decoding parses the Base64 URL string into a UTF-8 string. Encoding writes the string as a Base64 URL string.
See
- stringFromBase64String
Schema.StringFromBase64Url- a ready-made schema wrapping this transformation.
Signature
declare const stringFromBase64UrlString: Transformation<string, string>Example
(Converting Base64Url to a string)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.String, SchemaTransformation.stringFromBase64UrlString))Schema.decodeSync(schema)("aGVsbG8") // => "hello"stringFromHexString
Decodes a hex encoded string into a UTF-8 string and encodes it back.
When to use
Use when you need a schema transformation for text data transmitted as hexadecimal strings.
Details
Decoding parses the hex string into a UTF-8 string. Encoding writes the string as a hex string.
See
- stringFromBase64String
Schema.StringFromHex- a ready-made schema wrapping this transformation.
Signature
declare const stringFromHexString: Transformation<string, string>Example
(Converting hex to a string)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.String, SchemaTransformation.stringFromHexString))Schema.decodeSync(schema)("68656c6c6f") // => "hello"stringFromUriComponent
Decodes a URI component encoded string into a UTF-8 string and encodes a UTF-8 string into a URI component encoded string.
When to use
Use when you need a schema transformation to store structured data in URL
query parameters or fragments, such as composing with Schema.parseJson to
round-trip JSON through a URL.
Details
Decoding calls decodeURIComponent and fails if the input contains malformed
percent-encoding sequences. Encoding calls encodeURIComponent.
See
- stringFromBase64String
Schema.StringFromUriComponent- a ready-made schema wrapping this transformation.
Signature
declare const stringFromUriComponent: Transformation<string, string>Example
(Defining a URI component schema)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.String, SchemaTransformation.stringFromUriComponent))Schema.decodeSync(schema)("hello%20world") // => "hello world"uint8ArrayFromBase64String
Decodes a Base64-encoded string into a Uint8Array and encodes a
Uint8Array back to a Base64 string.
When to use
Use when you need a schema transformation for binary data transmitted as Base64 strings (e.g. file uploads, API payloads).
Details
Decoding parses the Base64 string into bytes. Encoding writes the byte array as a Base64 string.
See
- fromJsonString
Schema.Uint8ArrayFromBase64- a ready-made schema wrapping this transformation.
Signature
declare const uint8ArrayFromBase64String: Transformation<Uint8Array<ArrayBufferLike>, string>Example
(Converting Base64 to a Uint8Array)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.Uint8Array, SchemaTransformation.uint8ArrayFromBase64String))Array.from(Schema.decodeSync(schema)("AQID")) // => [1, 2, 3]Guards
isTransformation
Returns true if u is a Transformation instance.
When to use
Use to check whether a value is already a schema transformation before wrapping it.
Details
- Pure predicate, no side effects.
- Acts as a TypeScript type guard.
See
Signature
declare function isTransformation(u: unknown): u is Transformation<any, any, unknown, unknown>Example
(Checking a value)
import { SchemaTransformation } from "effect"
SchemaTransformation.isTransformation(SchemaTransformation.trim()) // => trueSchemaTransformation.isTransformation({ decode: null, encode: null }) // => falseModels
Middleware
Middleware that wraps the entire parsing Effect pipeline for both
decode and encode directions.
When to use
Use when you need a schema middleware to catch or recover from parsing
errors (e.g. Schema.catchDecoding), run side effects around the parsing
pipeline, or access the full Effect rather than a single decoded value.
Details
Unlike Transformation, which operates on individual values via Getter,
Middleware receives the full Effect produced by the inner schema and can
intercept, modify, retry, or replace it.
decodereceives anEffect<Option<E>, Issue, RDE>and returnsEffect<Option<T>, Issue, RDT>.encodereceives anEffect<Option<T>, Issue, RET>and returnsEffect<Option<E>, Issue, REE>.flip()swaps the decode and encode functions, producing aMiddleware<E, T, ...>.
Typically constructed indirectly via Schema.middlewareDecoding or
Schema.middlewareEncoding rather than instantiating this class directly.
See
- Transformation — value-level bidirectional transformation
Signature
declare class Middleware<in out T, in out E, RDE, RDT, RET, REE> { constructor<in out T, in out E, RDE, RDT, RET, REE>(decode: (effect: Effect<Option<E>, Issue, RDE>, options: ParseOptions) => Effect<Option<T>, Issue, RDT>, encode: (effect: Effect<Option<T>, Issue, RET>, options: ParseOptions) => Effect<Option<E>, Issue, REE>); readonly _tag: "Middleware"; readonly decode: (effect: Effect<Option<E>, Issue, RDE>, options: ParseOptions) => Effect<Option<T>, Issue, RDT>; readonly encode: (effect: Effect<Option<T>, Issue, RET>, options: ParseOptions) => Effect<Option<E>, Issue, REE>; flip(): Middleware<E, T, RET, REE, RDE, RDT>;}Example
(Creating a middleware that falls back on decode failure)
import { Effect, Option, SchemaIssue, SchemaTransformation } from "effect"
const fallback = new SchemaTransformation.Middleware<string, string, never, never, never, never>( (effect) => Effect.catch(effect, () => Effect.succeed(Option.some("fallback"))), (effect) => effect)const issue = new SchemaIssue.InvalidValue({ message: "Missing value" })await Effect.runPromise(fallback.decode(Effect.fail(issue), {})) // => Option.some("fallback")Transformation
Represents a bidirectional transformation between a decoded type T and an encoded
type E, built from a pair of Getters.
When to use
Use when you need a schema transformation that defines how a schema converts between two representations.
- You want to compose multiple transformations into a pipeline.
- You want to flip a transformation to swap decode/encode.
Details
This is the primary building block for Schema.decodeTo, Schema.encodeTo,
Schema.decode, Schema.encode, and Schema.link. Each direction is a
SchemaGetter.Getter that handles optionality, failure, and Effect services.
- Immutable —
flip()andcompose()return new instances. flip()swaps the decode and encode getters.compose(other)chains:this.decodethenother.decodefor decoding,other.encodethenthis.encodefor encoding.
See
- make — construct from
{ decode, encode }getters - transform — construct from pure functions
- transformOrFail — construct from effectful functions
- Middleware — effect-pipeline-level alternative
Signature
declare class Transformation<in out T, in out E, RD = never, RE = never> { constructor<in out T, in out E, RD = never, RE = never>(decode: Getter<T, E, RD>, encode: Getter<E, T, RE>); readonly _tag: "Transformation"; readonly "~effect/SchemaTransformation/Transformation": "~effect/SchemaTransformation/Transformation"; readonly decode: Getter<T, E, RD>; readonly encode: Getter<E, T, RE>; compose<T2, RD2, RE2>(other: Transformation<T2, T, RD2, RE2>): Transformation<T2, E, RD | RD2, RE | RE2>; flip(): Transformation<E, T, RE, RD>;}Example
(Composing two transformations)
import { SchemaTransformation } from "effect"
const trimAndLower = SchemaTransformation.trim().compose( SchemaTransformation.toLowerCase())trimAndLower._tag // => "Transformation"Transforming
bigDecimalFromString
Decodes a string into a BigDecimal and encodes a BigDecimal back to
its string representation.
When to use
Use when you need a schema transformation to parse decimal number strings from APIs or user input.
Details
Decoding calls BigDecimal.fromString(s) and fails with InvalidValue if
the string is not a valid BigDecimal representation. Encoding returns
BigDecimal.format(bd).
Signature
declare const bigDecimalFromString: Transformation<BigDecimal.BigDecimal, string>capitalize
Transforms strings by capitalizing the first character on decode. Encode is passthrough.
When to use
Use when you need a schema transformation to normalize display names or titles.
Details
Decoding uppercases the first character and leaves the rest unchanged. Encoding is passthrough.
See
Signature
declare function capitalize(): Transformation<string, string>Example
(Capitalizing on decode)
import { Schema, SchemaTransformation } from "effect"
const Capitalized = Schema.String.pipe( Schema.decode(SchemaTransformation.capitalize()))Schema.decodeSync(Capitalized)("hello") // => "Hello"dateTimeUtcFromString
Decodes a date-time string into a DateTime.Utc and encodes it back to an ISO
string.
When to use
Use when you need a schema transformation to decode date-time strings to a
normalized DateTime.Utc and encode back as a UTC ISO string.
Details
Decode accepts strings supported by DateTime.make, converts the result to
UTC, and fails with InvalidValue when parsing fails. Encode uses
DateTime.formatIso.
See
- dateFromString for decoding into JavaScript
Date - dateTimeZonedFromString for ISO strings that should preserve zoned date-time information
Signature
declare const dateTimeUtcFromString: Transformation<DateTime.Utc, string>dateTimeZonedFromString
Decodes a zoned date-time string into a DateTime.Zoned and encodes it back
to an ISO zoned string.
When to use
Use when you need a schema transformation for ISO zoned date-time strings
that decode to DateTime.Zoned and encode with DateTime.formatIsoZoned.
Details
Decode uses DateTime.makeZonedFromString and fails with InvalidValue when
the input is not a valid zoned date-time. Encode uses
DateTime.formatIsoZoned.
See
- dateTimeUtcFromString for date-time strings that should decode to
DateTime.Utcand encode as UTC ISO strings
Signature
declare const dateTimeZonedFromString: Transformation<DateTime.Zoned, string>durationFromMillis
Decodes a number of milliseconds into a Duration and encodes a Duration
back to milliseconds.
When to use
Use when you need a schema transformation to decode timeouts, delays, elapsed intervals, or other duration values stored as millisecond counts.
Details
Decode creates a duration from the number, and encode returns the duration length in milliseconds.
See
Signature
declare const durationFromMillis: Transformation<Duration.Duration, number>Example
(Converting milliseconds to a Duration)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.Number.pipe( Schema.decodeTo(Schema.Duration, SchemaTransformation.durationFromMillis))String(Schema.decodeSync(schema)(5000)) // => "5000 millis"durationFromNanos
Decodes a bigint (nanoseconds) into a Duration and encodes a
Duration back to bigint nanoseconds.
When to use
Use when you need a schema transformation for nanosecond-precision timestamps or intervals.
Details
Decoding always succeeds and creates a Duration from nanoseconds. Encoding
fails with InvalidValue if the Duration cannot be represented as a
bigint, such as Duration.infinity.
See
Signature
declare const durationFromNanos: Transformation<Duration.Duration, bigint>Example
(Converting nanoseconds to a Duration)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.BigInt.pipe( Schema.decodeTo(Schema.Duration, SchemaTransformation.durationFromNanos))String(Schema.decodeSync(schema)(5n)) // => "5 nanos"durationFromString
Decodes a string into a Duration and encodes a Duration back to a
parseable string.
When to use
Use when you need a schema transformation to parse human-readable duration strings from APIs, config, or user input.
Details
Decoding accepts any string that Duration.fromInput can parse, including
"Infinity" and "-Infinity". Encoding returns String(duration),
producing strings such as "2000 millis" or "10 nanos" that round-trip
through the parser.
See
Signature
declare const durationFromString: Transformation<Duration.Duration, string>Example
(Converting a string to a Duration)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.Duration, SchemaTransformation.durationFromString))String(Schema.decodeSync(schema)("5 seconds")) // => "5000 millis"optionFromNullishOr
Decodes T | null | undefined into Option<T> and encodes Option<T>
back to T | null or T | undefined depending on the provided
options.onNoneEncoding (defaults to undefined).
When to use
Use when you need a schema transformation to convert nullish API fields to
Option when both null and undefined represent absence.
Details
Decoding maps null and undefined to Option.none() and all other values
to Option.some(value). Encoding maps Option.none() to null or
undefined according to options.onNoneEncoding, and maps
Option.some(value) to value. The transformation is pure and synchronous.
See
Signature
declare function optionFromNullishOr<T>(options?: { onNoneEncoding: null | undefined;}): Transformation<Option<T>, T | null | undefined>Example
(Converting nullish values to an Option and encoding None as null)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.NullishOr(Schema.String).pipe( Schema.decodeTo( Schema.Option(Schema.String), SchemaTransformation.optionFromNullishOr({ onNoneEncoding: null }) ))Schema.encodeSync(schema)(Option.none()) // => nulloptionFromNullOr
Decodes T | null into Option<T> and encodes Option<T> back to
T | null.
When to use
Use when you need a schema transformation to convert nullable API fields to
Option.
Details
Decoding maps null to Option.none() and non-null values to
Option.some(value). Encoding maps Option.none() to null and
Option.some(value) to value. The transformation is pure and synchronous.
See
Signature
declare function optionFromNullOr<T>(): Transformation<Option<T>, T | null>Example
(Converting nullable values to an Option)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.NullOr(Schema.String).pipe( Schema.decodeTo( Schema.Option(Schema.String), SchemaTransformation.optionFromNullOr() ))Schema.decodeSync(schema)(null) // => Option.none()optionFromOptional
Decodes optional values into Option<T> and encodes Option.none() back to
an omitted optional value.
When to use
Use when you need a schema transformation to convert optional (possibly
undefined) values to Option.
Details
Decoding maps an absent or undefined value to Some(None) and a present
value to Some(Some(v)). Encoding maps Some(None) to None to omit the
value, and maps Some(Some(v)) to Some(v). This uses
transformOptional under the hood and filters out undefined on decode.
See
Signature
declare function optionFromOptional<T>(): Transformation<Option<T>, T | undefined>Example
(Converting an optional value to an Option)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.Struct({ age: Schema.optional(Schema.Number).pipe( Schema.decodeTo( Schema.Option(Schema.Number), SchemaTransformation.optionFromOptional() ) )})Schema.decodeSync(schema)({ age: undefined }).age // => Option.none()optionFromOptionalKey
Decodes an optional struct key into Option<T> and encodes Option<T>
back to an optional key.
When to use
Use when you need a schema transformation to convert optional struct keys
(declared with Schema.optionalKey) to Option values.
Details
Decoding maps an absent key (None) to Some(None) and a present key
(Some(v)) to Some(Some(v)). Encoding maps Some(None) to None to omit
the key, and maps Some(Some(v)) to Some(v). This uses
transformOptional under the hood.
See
Signature
declare function optionFromOptionalKey<T>(): Transformation<Option<T>, T>Example
(Converting an optional key to an Option)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.Struct({ name: Schema.optionalKey(Schema.String).pipe( Schema.decodeTo( Schema.Option(Schema.String), SchemaTransformation.optionFromOptionalKey() ) )})Schema.decodeSync(schema)({}).name // => Option.none()optionFromUndefinedOr
Decodes T | undefined into Option<T> and encodes Option.none() back to
undefined.
When to use
Use when you need a schema transformation to convert API fields that use
undefined for absence to Option.
Details
Decoding maps undefined to Option.none() and non-undefined values to
Option.some(value). Encoding maps Option.none() to undefined and
Option.some(value) to value. The transformation is pure and synchronous.
See
Signature
declare function optionFromUndefinedOr<T>(): Transformation<Option<T>, T | undefined>Example
(Converting undefined-or values to an Option)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.UndefinedOr(Schema.String).pipe( Schema.decodeTo( Schema.Option(Schema.String), SchemaTransformation.optionFromUndefinedOr() ))Schema.decodeSync(schema)(undefined) // => Option.none()snakeToCamel
Transforms strings by converting snake_case to camelCase on decode and camelCase to snake_case on encode.
When to use
Use when you need a schema transformation to convert API field names between snake_case and camelCase conventions.
Details
Decoding converts values such as "my_field_name" to "myFieldName".
Encoding converts values such as "myFieldName" back to "my_field_name".
The transformation is round-trippable for standard snake_case and camelCase.
See
Signature
declare function snakeToCamel(): Transformation<string, string>Example
(Converting snake case to camel case)
import { Schema, SchemaTransformation } from "effect"
const SnakeToCamel = Schema.String.pipe( Schema.decode(SchemaTransformation.snakeToCamel()))Schema.decodeSync(SnakeToCamel)("user_name") // => "userName"splitKeyValue
Transforms a string into a record of key-value pairs and encodes a record of key-value pairs into a string.
When to use
Use when you need a schema transformation to parse query-string-like or config-file-like strings into records.
Details
Decoding splits the string by separator (default ",") into pairs, then
splits each pair by keyValueSeparator (default "="). Encoding joins the
record back into a string using the same separators. The transformation is
round-trippable when keys and values do not contain the separators.
See
Signature
declare function splitKeyValue(options?: { readonly keyValueSeparator?: string; readonly separator?: string;}): Transformation<Record<string, string>, string>Example
(Parsing key-value pairs)
import { Schema, SchemaTransformation } from "effect"
const Config = Schema.String.pipe( Schema.decodeTo( Schema.Record(Schema.String, Schema.String), SchemaTransformation.splitKeyValue({ separator: ";", keyValueSeparator: ":" }) ))Schema.decodeSync(Config)("host:localhost;port:3000") // => { host: "localhost", port: "3000" }timeZoneFromString
Decodes a string into a DateTime.TimeZone and encodes a time zone back to
its string representation.
When to use
Use when you need a schema transformation to accept either an IANA time-zone
identifier or an offset string and produce a general DateTime.TimeZone.
Details
Accepted decode inputs include valid IANA identifiers and offset strings such
as "+03:00". Decode fails with InvalidValue when the string cannot be
parsed as a time zone.
See
- timeZoneNamedFromString for IANA named-zone strings only
- timeZoneOffsetFromNumber for fixed-offset zones encoded as numbers
Signature
declare const timeZoneFromString: Transformation<DateTime.TimeZone, string>timeZoneNamedFromString
Decodes an IANA time-zone identifier string into a
DateTime.TimeZone.Named and encodes a named time zone back to its id.
When to use
Use when you need a schema transformation to accept only IANA time-zone
identifier strings and produce DateTime.TimeZone.Named values.
Details
Decode fails with InvalidValue when the string is not a valid IANA time-zone
identifier.
See
- timeZoneFromString for time-zone strings that may be either IANA identifiers or offset strings
Signature
declare const timeZoneNamedFromString: Transformation<DateTime.TimeZone.Named, string>timeZoneOffsetFromNumber
Decodes a numeric time-zone offset in milliseconds into a
DateTime.TimeZone.Offset and encodes it back to the offset number.
When to use
Use when you need a schema transformation to represent fixed-offset time zones with numeric millisecond offsets.
Details
Decode uses DateTime.zoneMakeOffset; encode returns the offset's offset
field.
See
- timeZoneFromString for IANA or offset string encodings
- timeZoneNamedFromString for IANA named-zone strings
Signature
declare const timeZoneOffsetFromNumber: Transformation<DateTime.TimeZone.Offset, number>toLowerCase
Transforms strings by lowercasing on decode. Encode is passthrough.
When to use
Use when you need a schema transformation to normalize strings to lowercase (e.g. email addresses).
Details
Decoding applies String.prototype.toLowerCase(). Encoding is passthrough.
This is not round-trippable if the original had uppercase characters.
See
Signature
declare function toLowerCase(): Transformation<string, string>Example
(Lowercasing on decode)
import { Schema, SchemaTransformation } from "effect"
const Lowered = Schema.String.pipe( Schema.decode(SchemaTransformation.toLowerCase()))Schema.decodeSync(Lowered)("HELLO") // => "hello"toUpperCase
Transforms strings by uppercasing on decode. Encode is passthrough.
When to use
Use when you need a schema transformation to normalize strings to uppercase (e.g. country codes).
Details
Decoding applies String.prototype.toUpperCase(). Encoding is passthrough.
This is not round-trippable if the original had lowercase characters.
See
Signature
declare function toUpperCase(): Transformation<string, string>Example
(Uppercasing on decode)
import { Schema, SchemaTransformation } from "effect"
const Uppered = Schema.String.pipe( Schema.decode(SchemaTransformation.toUpperCase()))Schema.decodeSync(Uppered)("hello") // => "HELLO"Creates a Transformation from pure (sync, infallible) decode and encode
functions.
When to use
Use when you need an infallible schema transformation that does not require Effect services.
Details
- Each function receives the input and returns the output directly.
- Skips
Noneinputs (missing keys) — functions are only called on present values. - Does not allocate Effects internally; uses optimized sync path.
See
- transformOrFail — for fallible or effectful transformations
- transformOptional — for transformations that handle missing keys
- passthrough — when no conversion is needed
Signature
declare function transform<T, E>(options: { readonly decode: (input: E) => T; readonly encode: (input: T) => E;}): Transformation<T, E>Example
(Converting between cents and dollars)
import { Schema, SchemaTransformation } from "effect"
const CentsFromDollars = Schema.Number.pipe( Schema.decodeTo( Schema.Number, SchemaTransformation.transform({ decode: (dollars) => dollars * 100, encode: (cents) => cents / 100 }) ))Schema.decodeSync(CentsFromDollars)(2.5) // => 250transformOptional
Creates a Transformation where decode and encode operate on Option
values, giving full control over missing-key handling.
When to use
Use when you need a schema transformation to produce or consume Option.None
for absent keys.
- You are working with optional struct fields.
Details
- Each function receives
Option<input>and returnsOption<output>. Option.Noneinput means the key is absent; returningOption.Noneomits the key from the output.- Pure and synchronous.
See
- transform — when you don't need Option-level control
- optionFromOptionalKey — built-in for the common optional-key-to-Option pattern
- optionFromOptional — built-in for optional (undefined) to Option
Signature
declare function transformOptional<T, E>(options: { readonly decode: (input: Option<E>) => Option<T>; readonly encode: (input: Option<T>) => Option<E>;}): Transformation<T, E>Example
(Converting an optional key to Option)
import { Option, Schema, SchemaTransformation } from "effect"
const schema = Schema.Struct({ a: Schema.optionalKey(Schema.Number).pipe( Schema.decodeTo( Schema.Option(Schema.Number), SchemaTransformation.transformOptional({ decode: Option.some, encode: Option.flatten }) ) )})Schema.decodeSync(schema)({}).a // => Option.none()transformOrFail
Creates a Transformation from effectful decode and encode functions that
can fail with Issue.
When to use
Use when you need a schema transformation that may fail or require Effect services.
Details
- Each function receives the input value and
ParseOptions. - Must return an
Effectthat succeeds with the output or fails withIssue. - Skips
Noneinputs (missing keys) — functions are only called on present values.
See
- transform — for infallible, pure transformations
- transformOptional — for transformations that handle missing keys
- make — for transformations from existing Getters
Signature
declare function transformOrFail<T, E, RD = never, RE = never>(options: { readonly decode: (e: E, options: ParseOptions) => Effect<T, Issue, RD>; readonly encode: (t: T, options: ParseOptions) => Effect<E, Issue, RE>;}): Transformation<T, E, RD, RE>Example
(Parsing a date string that can fail)
import { Effect, Option, Schema, SchemaIssue, SchemaTransformation } from "effect"
const DateFromString = Schema.String.pipe( Schema.decodeTo( Schema.Date, SchemaTransformation.transformOrFail({ decode: (s, options) => { const d = new Date(s) return isNaN(d.getTime()) ? Effect.fail(new SchemaIssue.InvalidValue({ message: "Invalid date" }, s, options)) : Effect.succeed(d) }, encode: (d) => Effect.succeed(d.toISOString()) }) ))Schema.decodeSync(DateFromString)("2024-01-01").toISOString() // => "2024-01-01T00:00:00.000Z"Transforms strings by trimming whitespace on decode. Encode is passthrough (no change).
When to use
Use when you need a schema transformation to normalize user input by stripping leading/trailing whitespace.
Details
Decoding applies String.prototype.trim(). Encoding is passthrough and
returns the string unchanged. This is not round-trippable if the original had
whitespace.
See
Signature
declare function trim(): Transformation<string, string>Example
(Trimming on decode)
import { Schema, SchemaTransformation } from "effect"
const Trimmed = Schema.String.pipe( Schema.decode(SchemaTransformation.trim()))Schema.decodeSync(Trimmed)(" hello ") // => "hello"uncapitalize
Transforms strings by lowercasing the first character on decode. Encode is passthrough.
When to use
Use when you need a schema transformation to normalize identifiers or field names.
Details
Decoding lowercases the first character and leaves the rest unchanged. Encoding is passthrough.
See
Signature
declare function uncapitalize(): Transformation<string, string>Example
(Uncapitalizing on decode)
import { Schema, SchemaTransformation } from "effect"
const Uncapitalized = Schema.String.pipe( Schema.decode(SchemaTransformation.uncapitalize()))Schema.decodeSync(Uncapitalized)("Hello") // => "hello"urlFromString
Decodes a string into a URL and encodes a URL back to its href
string.
When to use
Use when you need a schema transformation to parse URL strings from user input or API responses.
Details
Decoding checks URL.canParse(s) and fails with InvalidValue if the string
is not a valid URL. Encoding returns url.href.
See
Signature
declare const urlFromString: Transformation<URL, string>Example
(Converting a string to a URL)
import { Schema, SchemaTransformation } from "effect"
const schema = Schema.String.pipe( Schema.decodeTo(Schema.URL, SchemaTransformation.urlFromString))Schema.decodeSync(schema)("https://example.com/path").href // => "https://example.com/path"