Skip to content

Flag.ts

Defines named options for command-line applications.

A Flag<A> describes how to read one named value from parsed command-line input, validate it, and produce an A. Flags are useful for inputs such as ports, verbosity switches, configuration files, output directories, choices, secrets, and repeated values. The helpers here build flags with aliases, defaults, optional values, prompts, configuration fallbacks, validation, and value transformations.

Since v4.0.0



Adds an alias to a flag, allowing it to be referenced by multiple names.

Example (Adding flag aliases)

import { Flag } from "effect/unstable/cli"
// Flag can be used as both --verbose and -v
const verboseFlag = Flag.boolean("verbose").pipe(Flag.withAlias("v"))
// Multiple aliases can be chained
const helpFlag = Flag.boolean("help").pipe(Flag.withAlias("h"), Flag.withAlias("?"))

Signature

declare const withAlias: { <A>(alias: string): (self: Flag<A>) => Flag<A>; <A>(self: Flag<A>, alias: string): Flag<A> }

Source

Since v4.0.0

Provides an alternative flag if the first one fails to parse.

Example (Falling back to another flag)

import { Flag } from "effect/unstable/cli"
// Try parsing as integer, fallback to string
const valueFlag = Flag.orElse(Flag.integer("value"), () => Flag.string("value"))
// Multiple input sources with fallback
const configFlag = Flag.orElse(Flag.file("config"), () => Flag.string("config-url"))

Signature

declare const orElse: {
<B>(that: LazyArg<Flag<B>>): <A>(self: Flag<A>) => Flag<A | B>
<A, B>(self: Flag<A>, that: LazyArg<Flag<B>>): Flag<A | B>
}

Source

Since v4.0.0

Tries to parse with the first flag, then the second, returning a Result that indicates which succeeded.

Example (Returning fallback results)

import { Effect, Result } from "effect"
import { Flag } from "effect/unstable/cli"
// Try file path, fallback to URL
const sourceFlag = Flag.orElseResult(Flag.file("source"), () => Flag.string("source-url"))
const program = Effect.gen(function* () {
const [leftover, source] = yield* sourceFlag.parse({
arguments: [],
flags: { "source-url": ["https://google.com"] }
})
if (Result.isSuccess(source)) {
console.log("Using file:", source.success)
} else {
console.log("Using URL:", source.failure)
}
})

Signature

declare const orElseResult: {
<B>(that: LazyArg<Flag<B>>): <A>(self: Flag<A>) => Flag<Result.Result<A, B>>
<A, B>(self: Flag<A>, that: LazyArg<Flag<B>>): Flag<Result.Result<A, B>>
}

Source

Since v4.0.0

Adds a fallback config that is loaded when a required flag is missing.

Example (Falling back to config)

import { Config } from "effect"
import { Flag } from "effect/unstable/cli"
const verbose = Flag.boolean("verbose").pipe(Flag.withFallbackConfig(Config.boolean("VERBOSE")))

Signature

declare const withFallbackConfig: {
<B>(config: Config.Config<B>): <A>(self: Flag<A>) => Flag<A | B>
<A, B>(self: Flag<A>, config: Config.Config<B>): Flag<A | B>
}

Source

Since v4.0.0

Adds a fallback prompt that is shown when a required flag is missing.

Example (Falling back to prompts)

import { Flag, Prompt } from "effect/unstable/cli"
const name = Flag.string("name").pipe(Flag.withFallbackPrompt(Prompt.text({ message: "Name" })))

Signature

declare const withFallbackPrompt: {
<B>(prompt: Param.FallbackPrompt<B>): <A>(self: Flag<A>) => Flag<A | B>
<A, B>(self: Flag<A>, prompt: Param.FallbackPrompt<B>): Flag<A | B>
}

Source

Since v4.0.0

Creates a boolean flag that can be enabled or disabled.

Example (Creating boolean flags)

import { Flag } from "effect/unstable/cli"
const verboseFlag = Flag.boolean("verbose")
// Usage: --verbose (true) or --no-verbose (false)

Signature

declare const boolean: (name: string) => Flag<boolean>

Source

Since v4.0.0

Creates a flag that accepts one of the provided string choices and returns the selected string.

When to use

Use when you need to define a named CLI flag with fixed string choices and no custom value mapping.

Gotchas

An empty choices array compiles, but no input value can parse successfully.

See

  • choiceWithValue for mapping accepted strings to different typed values

Signature

declare const choice: <const Choices extends ReadonlyArray<string>>(
name: string,
choices: Choices
) => Flag<Choices[number]>

Source

Since v4.0.0

Constructs option parameters that represent a choice between several inputs. Each tuple maps a string flag value to an associated typed value.

Example (Creating flag choices with values)

import { Flag } from "effect/unstable/cli"
// simple enum like choice mapping directly to string union
const color = Flag.choice("color", ["red", "green", "blue"])
// choice with custom value mapping
const logLevel = Flag.choiceWithValue("log-level", [
["debug", "Debug" as const],
["info", "Info" as const],
["error", "Error" as const]
])

Signature

declare const choiceWithValue: <const Choice extends ReadonlyArray<readonly [string, any]>>(
name: string,
choices: Choice
) => Flag<Choice[number][1]>

Source

Since v4.0.0

Creates a date flag that accepts date input in ISO format.

Example (Creating date flags)

import { Flag } from "effect/unstable/cli"
const startDateFlag = Flag.date("start-date")
// Usage: --start-date 2023-12-25

Signature

declare const date: (name: string) => Flag<Date>

Source

Since v4.0.0

Creates a directory path flag that accepts directory paths with optional existence validation.

Example (Creating directory flags)

import { Flag } from "effect/unstable/cli"
// Basic directory flag
const outputFlag = Flag.directory("output")
// Usage: --output ./build
// Directory that must exist
const sourceFlag = Flag.directory("source", { mustExist: true })
// Usage: --source ./src (directory must exist)

Signature

declare const directory: (name: string, options?: { readonly mustExist?: boolean | undefined }) => Flag<string>

Source

Since v4.0.0

Creates a file path flag that accepts file paths with optional existence validation.

Example (Creating file flags)

import { Flag } from "effect/unstable/cli"
// Basic file flag
const inputFlag = Flag.file("input")
// Usage: --input ./data.json
// File that must exist
const configFlag = Flag.file("config", { mustExist: true })
// Usage: --config ./config.yaml (file must exist)

Signature

declare const file: (name: string, options?: { readonly mustExist?: boolean | undefined }) => Flag<string>

Source

Since v4.0.0

Creates a flag that reads and parses the content of the specified file.

Details

The parser that is utilized will depend on the specified format, or the extension of the file passed on the command-line if no format is specified.

Example (Parsing file contents)

import { Flag } from "effect/unstable/cli"
// Will use the extension of the file passed on the command line to determine
// the parser to use
const config = Flag.fileParse("config")
// Will use the JSON parser
const jsonConfig = Flag.fileParse("json-config", { format: "json" })

Signature

declare const fileParse: (name: string, options?: Primitive.FileParseOptions | undefined) => Flag<unknown>

Source

Since v4.0.0

Creates a flag that reads and validates file content using the specified schema.

Example (Validating file contents)

import { Schema } from "effect"
import { Flag } from "effect/unstable/cli"
const ConfigSchema = Schema.Struct({
port: Schema.Number,
host: Schema.String
})
const config = Flag.fileSchema("config", ConfigSchema, { format: "json" })

Signature

declare const fileSchema: <A>(
name: string,
schema: Schema.ConstraintDecoder<A, Environment>,
options?: Primitive.FileSchemaOptions | undefined
) => Flag<A>

Source

Since v4.0.0

Creates a flag that reads and returns file content as a string.

Example (Reading file text)

import { Flag } from "effect/unstable/cli"
const config = Flag.fileText("config-file")
// --config-file ./app.json will read the file content

Signature

declare const fileText: (name: string) => Flag<string>

Source

Since v4.0.0

Creates a float flag that accepts decimal number input.

Example (Creating float flags)

import { Flag } from "effect/unstable/cli"
const rateFlag = Flag.float("rate")
// Usage: --rate 3.14

Signature

declare const float: (name: string) => Flag<number>

Source

Since v4.0.0

Creates an integer flag that accepts whole number input.

Example (Creating integer flags)

import { Flag } from "effect/unstable/cli"
const portFlag = Flag.integer("port")
// Usage: --port 8080

Signature

declare const integer: (name: string) => Flag<number>

Source

Since v4.0.0

Creates a flag that parses key=value pairs.

When to use

Use when you need a CLI flag that accepts one or more key=value configuration entries.

Details

Requires at least one key=value pair. Multiple pairs are merged into a single record.

Example (Parsing key-value pairs)

import { Flag } from "effect/unstable/cli"
const env = Flag.keyValuePair("env")
// --env FOO=bar --env BAZ=qux will parse to { FOO: "bar", BAZ: "qux" }

Signature

declare const keyValuePair: (name: string) => Flag<Record<string, string>>

Source

Since v4.0.0

Creates an empty sentinel flag that always fails to parse. This is useful for creating placeholder flags or for combinators.

Example (Creating sentinel flags)

import { Flag } from "effect/unstable/cli"
const makeValueFlag = (includeValue: boolean) => (includeValue ? Flag.string("value") : Flag.none)
console.log(makeValueFlag(true) === Flag.none) // false
console.log(makeValueFlag(false) === Flag.none) // true

Signature

declare const none: Flag<never>

Source

Since v4.0.0

Creates a path flag that accepts file system path input with validation options.

Example (Creating path flags)

import { Flag } from "effect/unstable/cli"
// Basic path flag
const pathFlag = Flag.path("config-path")
// File-only path that must exist
const fileFlag = Flag.path("input-file", {
pathType: "file",
mustExist: true
})
// Directory path with custom type name
const dirFlag = Flag.path("output-dir", {
pathType: "directory",
typeName: "OUTPUT_DIRECTORY"
})

Signature

declare const path: (
name: string,
options?: {
readonly pathType?: "file" | "directory" | "either" | undefined
readonly mustExist?: boolean | undefined
readonly typeName?: string | undefined
}
) => Flag<string>

Source

Since v4.0.0

Creates a string flag whose parsed value is wrapped in Redacted.Redacted so stringification and logging redact the value.

Gotchas

Values supplied on the command line may still be visible to the operating system or shell history.

Example (Creating redacted flags)

import { Effect, Redacted } from "effect"
import { Flag } from "effect/unstable/cli"
const passwordFlag = Flag.redacted("password")
const program = Effect.gen(function* () {
const [leftover, password] = yield* passwordFlag.parse({
arguments: [],
flags: { password: ["abc123"] }
})
const value = Redacted.value(password) // Access the underlying value
console.log("Password length:", value.length)
})

Signature

declare const redacted: (name: string) => Flag<Redacted.Redacted<string>>

Source

Since v4.0.0

Creates a string flag that accepts text input.

Example (Creating string flags)

import { Flag } from "effect/unstable/cli"
const nameFlag = Flag.string("name")
// Usage: --name "John Doe"

Signature

declare const string: (name: string) => Flag<string>

Source

Since v4.0.0

Filters a flag value based on a predicate, failing with a custom error if the predicate returns false.

Example (Filtering parsed values)

import { Flag } from "effect/unstable/cli"
// Ensure port is in valid range
const portFlag = Flag.integer("port").pipe(
Flag.filter(
(port) => port >= 1 && port <= 65535,
(port) => `Port ${port} is out of range (1-65535)`
)
)
// Ensure non-empty string
const nameFlag = Flag.string("name").pipe(
Flag.filter(
(name) => name.trim().length > 0,
() => "Name cannot be empty"
)
)

Signature

declare const filter: {
<A>(predicate: (a: A) => boolean, onFalse: (a: A) => string): (self: Flag<A>) => Flag<A>
<A>(self: Flag<A>, predicate: (a: A) => boolean, onFalse: (a: A) => string): Flag<A>
}

Source

Since v4.0.0

Transforms and filters a flag value, failing with a custom error if the transformation returns None.

Example (Filtering and transforming values)

import { Option } from "effect"
import { Flag } from "effect/unstable/cli"
// Parse positive integers only
const positiveInt = Flag.integer("count").pipe(
Flag.filterMap(
(n) => (n > 0 ? Option.some(n) : Option.none()),
(n) => `Expected positive integer, got ${n}`
)
)
// Parse valid email addresses
const emailFlag = Flag.string("email").pipe(
Flag.filterMap(
(email) => (email.includes("@") ? Option.some(email) : Option.none()),
(email) => `Invalid email address: ${email}`
)
)

Signature

declare const filterMap: {
<A, B>(f: (a: A) => Option.Option<B>, onNone: (a: A) => string): (self: Flag<A>) => Flag<B>
<A, B>(self: Flag<A>, f: (a: A) => Option.Option<B>, onNone: (a: A) => string): Flag<B>
}

Source

Since v4.0.0

Adds a description to a flag for help documentation.

Example (Adding help descriptions)

import { Flag } from "effect/unstable/cli"
const portFlag = Flag.integer("port").pipe(Flag.withDescription("The port number to listen on"))
const configFlag = Flag.file("config").pipe(Flag.withDescription("Path to the configuration file"))

Signature

declare const withDescription: {
<A>(description: string): (self: Flag<A>) => Flag<A>
<A>(self: Flag<A>, description: string): Flag<A>
}

Source

Since v4.0.0

Transforms the parsed value of a flag using a mapping function.

Example (Mapping parsed values)

import { Flag } from "effect/unstable/cli"
// Convert string to uppercase
const nameFlag = Flag.string("name").pipe(Flag.map((name) => name.toUpperCase()))
// Convert port to URL
const urlFlag = Flag.integer("port").pipe(Flag.map((port) => `http://localhost:${port}`))

Signature

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

Source

Since v4.0.0

Transforms the parsed value using an Effect that can perform IO operations.

Example (Mapping parsed values effectfully)

import { Effect, FileSystem } from "effect"
import { Flag } from "effect/unstable/cli"
// Read file size from path flag
const fileSizeFlag = Flag.file("input").pipe(
Flag.mapEffect(
Effect.fnUntraced(function* (path) {
const fs = yield* FileSystem.FileSystem
const stats = yield* Effect.orDie(fs.stat(path))
return stats.size
})
)
)

Signature

declare const mapEffect: {
<A, B>(f: (a: A) => Effect.Effect<B, CliError.CliError, Environment>): (self: Flag<A>) => Flag<B>
<A, B>(self: Flag<A>, f: (a: A) => Effect.Effect<B, CliError.CliError, Environment>): Flag<B>
}

Source

Since v4.0.0

Transforms the parsed value using a function that might throw, with error handling.

Example (Mapping thrown errors)

import { Flag } from "effect/unstable/cli"
// Parse JSON string with error handling
const jsonFlag = Flag.string("config").pipe(
Flag.mapTryCatch(
(json) => JSON.parse(json),
(error) => `Invalid JSON: ${error}`
)
)
// Parse URL with error handling
const urlFlag = Flag.string("url").pipe(
Flag.mapTryCatch(
(url) => new URL(url),
(error) => `Invalid URL: ${error}`
)
)

Signature

declare const mapTryCatch: {
<A, B>(f: (a: A) => B, onError: (error: unknown) => string): (self: Flag<A>) => Flag<B>
<A, B>(self: Flag<A>, f: (a: A) => B, onError: (error: unknown) => string): Flag<B>
}

Source

Since v4.0.0

Hides a flag from generated help output and shell completions while keeping it fully parseable on the command line.

When to use

Use when experimental or internal flags should be accepted but not advertised, such as --experimental-foo, debug toggles, or escape hatches that are not yet committed to the public CLI surface.

Example (Hiding a flag from help)

import { Flag } from "effect/unstable/cli"
// Flag still parses --experimental-foo, but it does not appear in --help.
const experimental = Flag.boolean("experimental-foo").pipe(Flag.withHidden)

Signature

declare const withHidden: <A>(self: Flag<A>) => Flag<A>

Source

Since v4.0.0

Sets a custom metavar (placeholder name) for the flag in help documentation.

Details

The metavar is displayed in usage text to indicate what value the user should provide. For example, --output FILE shows FILE as the metavar.

Example (Setting metavars)

import { Flag } from "effect/unstable/cli"
const databaseFlag = Flag.string("database-url").pipe(
Flag.withMetavar("URL"),
Flag.withDescription("Database connection URL")
)
// In help: --database-url URL
const timeoutFlag = Flag.integer("timeout").pipe(Flag.withMetavar("SECONDS"))
// In help: --timeout SECONDS

Signature

declare const withMetavar: {
<A>(metavar: string): (self: Flag<A>) => Flag<A>
<A>(self: Flag<A>, metavar: string): Flag<A>
}

Source

Since v4.0.0

Represents a command-line flag.

Signature

export interface Flag<A> extends Param.Param<typeof Param.flagKind, A> {}

Source

Since v4.0.0

Makes a flag optional, returning an Option type that can be None if not provided.

Example (Making flags optional)

import { Effect, Option } from "effect"
import { Flag } from "effect/unstable/cli"
const optionalPort = Flag.optional(Flag.integer("port"))
const program = Effect.gen(function* () {
const [leftover, port] = yield* optionalPort.parse({
arguments: [],
flags: { port: ["4000"] }
})
if (Option.isSome(port)) {
console.log("Port specified:", port.value)
} else {
console.log("No port specified, using default")
}
})

Signature

declare const optional: <A>(param: Flag<A>) => Flag<Option.Option<A>>

Source

Since v4.0.0

Provides a default value for a flag when it’s not specified.

Example (Providing default values)

import { Flag } from "effect/unstable/cli"
const portFlag = Flag.integer("port").pipe(Flag.withDefault(8080))
// If --port is not provided, defaults to 8080
const hostFlag = Flag.string("host").pipe(Flag.withDefault("localhost"))
// If --host is not provided, defaults to "localhost"

Signature

declare const withDefault: {
<const B>(defaultValue: B | Effect.Effect<B, CliError.CliError, Environment>): <A>(self: Flag<A>) => Flag<A | B>
<A, const B>(self: Flag<A>, defaultValue: B | Effect.Effect<B, CliError.CliError, Environment>): Flag<A | B>
}

Source

Since v4.0.0

Ensures a flag is specified at least a minimum number of times.

Example (Requiring repeated values)

import { Flag } from "effect/unstable/cli"
const sourceFlag = Flag.atLeast(Flag.file("source"), 2)
// Requires at least 2 source files
// Usage: --source file1.ts --source file2.ts
const tagFlag = Flag.string("tag").pipe(Flag.atLeast(1))
// Requires at least 1 tag

Signature

declare const atLeast: {
<A>(min: number): (self: Flag<A>) => Flag<ReadonlyArray<A>>
<A>(self: Flag<A>, min: number): Flag<ReadonlyArray<A>>
}

Source

Since v4.0.0

Ensures a flag is specified at most a maximum number of times.

Example (Limiting repeated values)

import { Flag } from "effect/unstable/cli"
const warningFlag = Flag.atMost(Flag.string("warning"), 3)
// Allows up to 3 warning flags
// Usage: --warning w1 --warning w2 --warning w3
const debugFlag = Flag.string("debug").pipe(Flag.atMost(1))
// Allows at most 1 debug flag

Signature

declare const atMost: {
<A>(max: number): (self: Flag<A>) => Flag<ReadonlyArray<A>>
<A>(self: Flag<A>, max: number): Flag<ReadonlyArray<A>>
}

Source

Since v4.0.0

Ensures a flag is specified between a minimum and maximum number of times.

Example (Bounding repeated values)

import { Flag } from "effect/unstable/cli"
const hostFlag = Flag.between(Flag.string("host"), 1, 3)
// Requires 1-3 host flags
// Usage: --host host1 --host host2
const excludeFlag = Flag.string("exclude").pipe(Flag.between(0, 5))
// Allows 0-5 exclude patterns

Signature

declare const between: {
<A>(min: number, max: number): (self: Flag<A>) => Flag<ReadonlyArray<A>>
<A>(self: Flag<A>, min: number, max: number): Flag<ReadonlyArray<A>>
}

Source

Since v4.0.0

Validates and transforms a flag value using a Schema codec.

Example (Validating with schemas)

import { Schema } from "effect"
import { Flag } from "effect/unstable/cli"
const isEmail = Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, {
message: "Must be a valid email address"
})
// Parse and validate email with custom schema
const EmailSchema = Schema.String.pipe(Schema.check(isEmail))
const emailFlag = Flag.string("email").pipe(Flag.withSchema(EmailSchema))
// Parse JSON configuration with schema validation
const ConfigSchema = Schema.Struct({
port: Schema.Number,
host: Schema.String,
ssl: Schema.optional(Schema.Boolean)
}).pipe(Schema.fromJsonString)
const configFlag = Flag.string("config").pipe(Flag.withSchema(ConfigSchema))

Signature

declare const withSchema: {
<A, B>(schema: Schema.Codec<B, A, Environment, Environment>): (self: Flag<A>) => Flag<B>
<A, B>(self: Flag<A>, schema: Schema.Codec<B, A, Environment, Environment>): Flag<B>
}

Source

Since v4.0.0