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<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 }

float

Added in v4.0.0 Source

Creates a primitive that parses floating-point numbers from string input.

Signature

declare const float: Primitive<number>

Example

(Parsing floating-point 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.float.parse("3.14"),
Primitive.float.parse("-42.5"),
Primitive.float.parse("0")
])
await Effect.runPromise(parseFloat.pipe(Effect.provide(CliTestLayer))) // => [3.14, -42.5, 0]

integer

Added in v4.0.0 Source

Creates a primitive that parses integer numbers from string input.

Signature

declare const integer: 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.integer.parse("42"),
Primitive.integer.parse("-123"),
Primitive.integer.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.

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" }]

none

Added in v4.0.0 Source

Creates a sentinel primitive that always fails to parse a value.

When to use

Use when you need a CLI primitive for flags that do not accept values.

Signature

declare const none: 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*() {
// This will always fail - useful for boolean flags
return yield* Primitive.none.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.integer) // => "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.integer.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.