Skip to content
Effect Days 2026 Get your ticket

Primitive

Parses raw command-line strings into typed values.

A Primitive<A> receives one string and returns an Effect that either produces an A or fails with a parser message. Argument and Flag build on these primitives to add names, aliases, defaults, prompts, configuration fallbacks, repetition, and help metadata. Primitive parsers cover common scalar values, paths, files, structured config files, schema-decoded input, redacted values, and key-value pairs.

19 exports Added in v4.0.0 Source

Constructors

Boolean

Added in v4.0.0 Source

Creates a primitive that parses boolean values from string input.

Details

Recognizes various forms of true/false values:

  • True values: "true", "1", "y", "yes", "on"
  • False values: "false", "0", "n", "no", "off"

Signature

declare const Boolean: Primitive<boolean>

Example

(Parsing boolean values)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseBoolean = Effect.all([
Primitive.Boolean.parse("true"),
Primitive.Boolean.parse("yes"),
Primitive.Boolean.parse("false"),
Primitive.Boolean.parse("0")
])
await Effect.runPromise(parseBoolean.pipe(Effect.provide(CliTestLayer))) // => [true, true, false, false]

Choice

Added in v4.0.0 Source

Creates a primitive that accepts only specific choice values mapped to custom types.

Signature

declare function Choice<A>(choices: readonly Array<readonly [string, A]>): Primitive<A>

Example

(Parsing choices)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
type LogLevel = "debug" | "info" | "warn" | "error"
const logLevelPrimitive = Primitive.Choice<LogLevel>([
["debug", "debug"],
["info", "info"],
["warn", "warn"],
["error", "error"]
])
const parseLogLevel = Effect.all([
logLevelPrimitive.parse("info"),
logLevelPrimitive.parse("debug")
])
await Effect.runPromise(parseLogLevel.pipe(Effect.provide(CliTestLayer))) // => ["info", "debug"]

Date

Added in v4.0.0 Source

Creates a primitive that parses Date objects from string input.

Signature

declare const Date: Primitive<globalThis.Date>

Example

(Parsing date values)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseDate = Effect.gen(function*() {
const result = yield* Primitive.Date.parse("2023-12-25")
return result.toISOString()
})
await Effect.runPromise(parseDate.pipe(Effect.provide(CliTestLayer))) // => "2023-12-25T00:00:00.000Z"

FileParse

Added in v4.0.0 Source

Creates a primitive that reads a file and parses its content as structured data.

Details

The parser is selected from options.format when provided, otherwise from the file extension. Supported formats include INI, JSON, TOML, YAML, and YML.

Signature

declare function FileParse(options?: FileParseOptions): Primitive<unknown>

Example

(Parsing file content)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const services = Layer.mergeAll(
Path.layer,
FileSystem.layerNoop({
exists: () => Effect.succeed(true),
stat: () => Effect.succeed({ type: "File" } as FileSystem.File.Info),
readFileString: () => Effect.succeed('{"private":true}')
}),
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const jsonFilePrimitive = Primitive.FileParse({ format: "json" })
const loadConfig = Effect.gen(function*() {
const config = yield* jsonFilePrimitive.parse("./package.json")
return config as { private: boolean }
}).pipe(Effect.provide(services))
await Effect.runPromise(loadConfig) // => { private: true }

FileSchema

Added in v4.0.0 Source

Reads and parses file content using the specified schema.

Signature

declare function FileSchema<A>(schema: ConstraintDecoder<A, Environment>, options?: {
readonly errorFormatter?: Formatter<string>;
readonly format?: "json" | "ini" | "toml" | "yaml";
}): Primitive<A>

Example

(Parsing file content with a schema)

import { Effect, FileSystem, Layer, Path, Schema, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const services = Layer.mergeAll(
Path.layer,
FileSystem.layerNoop({
exists: () => Effect.succeed(true),
stat: () => Effect.succeed({ type: "File" } as FileSystem.File.Info),
readFileString: () => Effect.succeed('{"private":true}')
}),
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const ConfigSchema = Schema.Struct({
private: Schema.Boolean
})
const jsonConfigPrimitive = Primitive.FileSchema(ConfigSchema, {
format: "json"
})
const loadConfig = Effect.gen(function*() {
return yield* jsonConfigPrimitive.parse("./package.json")
}).pipe(Effect.provide(services))
await Effect.runPromise(loadConfig) // => { private: true }

FileText

Added in v4.0.0 Source

Creates a primitive that reads and returns the contents of a file as a string.

Signature

declare const FileText: Primitive<string>

Example

(Reading file text)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const services = Layer.mergeAll(
Path.layer,
FileSystem.layerNoop({
exists: () => Effect.succeed(true),
stat: () => Effect.succeed({ type: "File" } as FileSystem.File.Info),
readFileString: () => Effect.succeed('{"private":true}')
}),
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const readConfigFile = Effect.gen(function*() {
const content = yield* Primitive.FileText.parse("./package.json")
return JSON.parse(content) as { private: boolean }
}).pipe(Effect.provide(services))
await Effect.runPromise(readConfigFile) // => { private: true }

Finite

Added in v4.0.0 Source

Creates a primitive that parses finite numbers from string input.

Signature

declare const Finite: Primitive<number>

Example

(Parsing finite numbers)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseFloat = Effect.all([
Primitive.Finite.parse("3.14"),
Primitive.Finite.parse("-42.5"),
Primitive.Finite.parse("0")
])
await Effect.runPromise(parseFloat.pipe(Effect.provide(CliTestLayer))) // => [3.14, -42.5, 0]

Int

Added in v4.0.0 Source

Creates a primitive that parses integer numbers from string input.

Signature

declare const Int: Primitive<number>

Example

(Parsing integer values)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseInteger = Effect.all([
Primitive.Int.parse("42"),
Primitive.Int.parse("-123"),
Primitive.Int.parse("0")
])
await Effect.runPromise(parseInteger.pipe(Effect.provide(CliTestLayer))) // => [42, -123, 0]

KeyValuePair

Added in v4.0.0 Source

Parses a single key=value pair into a record object.

Details

Splits at the first =. Keys and values must be non-empty; values may contain =.

Signature

declare const KeyValuePair: Primitive<Record<string, string>>

Example

(Parsing key-value pairs)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseKeyValue = Effect.all([
Primitive.KeyValuePair.parse("name=john"),
Primitive.KeyValuePair.parse("port=3000"),
Primitive.KeyValuePair.parse("debug=true")
])
const result = await Effect.runPromise(parseKeyValue.pipe(Effect.provide(CliTestLayer)))
result // => [{ name: "john" }, { port: "3000" }, { debug: "true" }]

Never

Added in v4.0.0 Source

A primitive that always fails to parse.

Signature

declare const Never: Primitive<never>

Example

(Rejecting option values)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const program = Effect.gen(function*() {
return yield* Primitive.Never.parse("any-value")
})
await Effect.runPromise(Effect.flip(program).pipe(Effect.provide(CliTestLayer))) // => "This option does not accept values"

Path

Added in v4.0.0 Source

Creates a primitive that validates and resolves file system paths.

Signature

declare function Path(pathType: PathType, mustExist?: boolean): Primitive<string>

Example

(Parsing file system paths)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const services = Layer.mergeAll(
Path.layer,
FileSystem.layerNoop({
exists: () => Effect.succeed(true),
stat: () => Effect.succeed({ type: "File" } as FileSystem.File.Info)
}),
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const program = Effect.gen(function*() {
const filePrimitive = Primitive.Path("file", true)
const filePath = yield* filePrimitive.parse("./package.json")
return filePath.endsWith("/package.json")
}).pipe(Effect.provide(services))
await Effect.runPromise(program) // => true

Redacted

Added in v4.0.0 Source

Creates a primitive that wraps string input in Redacted.

Details

The wrapped value is hidden when formatted or inspected, while the original string remains available through the Redacted API when explicitly needed.

Signature

declare const Redacted: Primitive<Redacted_.Redacted<string>>

Example

(Parsing redacted values)

import { Effect, FileSystem, Layer, Path, Redacted, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseRedacted = Effect.gen(function*() {
const result = yield* Primitive.Redacted.parse("secret-password")
return [Redacted.value(result), String(result)] as const
})
await Effect.runPromise(parseRedacted.pipe(Effect.provide(CliTestLayer))) // => ["secret-password", "<redacted>"]

String

Added in v4.0.0 Source

Creates a primitive that accepts any string value without validation.

Signature

declare const String: Primitive<string>

Example

(Parsing string values)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const parseString = Effect.all([
Primitive.String.parse("hello world"),
Primitive.String.parse(""),
Primitive.String.parse("123")
])
await Effect.runPromise(parseString.pipe(Effect.provide(CliTestLayer))) // => ["hello world", "", "123"]

Getters

getTypeName

Added in v4.0.0 Source

Gets a human-readable type name for a primitive.

When to use

Use when you need the display type name for a Primitive, such as when generating CLI help documentation.

Signature

declare function getTypeName<A>(primitive: Primitive<A>): string

Example

(Getting primitive type names)

import { Primitive } from "effect/unstable/cli"
Primitive.getTypeName(Primitive.String) // => "string"
Primitive.getTypeName(Primitive.Int) // => "integer"
Primitive.getTypeName(Primitive.Boolean) // => "boolean"
Primitive.getTypeName(Primitive.Date) // => "date"
Primitive.getTypeName(Primitive.KeyValuePair) // => "key=value"
const logLevelChoice = Primitive.Choice([
["debug", "debug"],
["info", "info"]
])
Primitive.getTypeName(logLevelChoice) // => "choice"

Models

PathType type

Added in v4.0.0 Source

Specifies the type of path validation to perform.

Signature

type PathType = "file" | "directory" | "either"

Example

(Choosing path validation)

import { Primitive } from "effect/unstable/cli"
// Only accept files
const filePath = Primitive.Path("file", true)
// Only accept directories
const dirPath = Primitive.Path("directory", true)
// Accept either files or directories
const anyPath = Primitive.Path("either", false)
const tags = [filePath._tag, dirPath._tag, anyPath._tag] // => ["Path", "Path", "Path"]

Primitive interface

Added in v4.0.0 Source

Represents a primitive type that can parse string input into a typed value.

Signature

interface Primitive<out A> extends Variance<A> {
readonly _tag: string;
readonly parse: (value: string) => Effect<A, string, Environment>;
}

Example

(Parsing values with primitives)

import { Effect, FileSystem, Layer, Path, Stdio, Terminal } from "effect"
import { Primitive } from "effect/unstable/cli"
import { ChildProcessSpawner } from "effect/unstable/process"
const CliTestLayer = Layer.mergeAll(
FileSystem.layerNoop({}),
Path.layer,
Stdio.layerTest({}),
Layer.succeed(Terminal.Terminal, Terminal.make({
columns: Effect.succeed(80),
rows: Effect.succeed(24),
readInput: Effect.die("unused"),
readLine: Effect.die("unused"),
display: () => Effect.void
})),
Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() => Effect.die("unused"))
)
)
const program = Effect.gen(function*() {
const stringResult = yield* Primitive.String.parse("hello")
const numberResult = yield* Primitive.Int.parse("42")
const boolResult = yield* Primitive.Boolean.parse("true")
return [stringResult, numberResult, boolResult] as const
})
await Effect.runPromise(program.pipe(Effect.provide(CliTestLayer))) // => ["hello", 42, true]

Options

FileParseOptions type

Added in v4.0.0 Source

Represents options which can be provided to methods that deal with parsing file content.

Signature

type FileParseOptions = {
readonly format?: "ini" | "json" | "toml" | "yaml";
}

FileSchemaOptions type

Added in v4.0.0 Source

Represents options which can be provided to methods that deal with parsing file content and decoding the file content with a Schema.

Signature

type FileSchemaOptions = Struct.Simplify<FileParseOptions & {
readonly errorFormatter?: Formatter<string>;
}>

Other

Primitive

Added in v4.0.0 Source

Namespace containing type-level helpers for Primitive.