Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Path unstable

Provides path operations through the Effect environment.

The Path service works with file system paths without tying code to one concrete platform module. It exposes common operations such as joining, normalizing, parsing, formatting, resolving, and converting paths to or from file URLs. This module includes the service interface, parsed path type, service tag, runtime marker, and built-in POSIX path layer.

6 exports Since v4.0.0 Source

Constructors

make

unstable
Since v4.0.0

Creates a Path service from platform path operations.

When to use

Use to build a Path implementation, such as a platform layer or a test double, without implementing the operations that can be derived from the others.

Details

Adds the Path type marker and derives resolveWithin from the provided parse, resolve, relative, isAbsolute, and sep, so containment follows the same platform rules as those operations.

See

  • layer for the built-in POSIX Path service layer

Signature

declare function make(impl: Omit<Path, typeof TypeId | "resolveWithin">): Path

Layers

layer

unstable
Since v4.0.0

Layer that provides the built-in POSIX Path implementation.

When to use

Use when you need an effect that requires the Path service to run with the built-in POSIX path implementation.

Details

The layer provides a static service whose separator is / and whose operations use POSIX path semantics.

See

  • Path for accessing the Path service from an effect

Signature

declare const layer: Layer.Layer<Path>

Other

Path

unstable
Since v4.0.0

Namespace containing types associated with the Path service.

When to use

Use to reference types associated with path parsing and formatting.

Example Working with parsed paths

import { Effect, Path } from "effect"
// Access types and utilities in the Path namespace
const program = Effect.gen(function*() {
const path = yield* Path.Path
// Parse a path and get a Path.Parsed object
const parsed = path.parse("/home/user/file.txt")
// The parsed object conforms to the Path.Parsed interface
const exampleParsed = {
root: "/",
dir: "/home/user",
base: "file.txt",
ext: ".txt",
name: "file"
}
return [parsed.base, exampleParsed.base]
})
Effect.runSync(Effect.provide(program, Path.layer)) // => ["file.txt", "file.txt"]

Services

Path

unstable
Since v4.0.0

Service tag for accessing the current Path implementation.

When to use

Use when you need path operations supplied by an effect's environment.

Signature

declare const Path: Service<Path, Path>

Example Providing a custom Path service

import { Effect, Layer, Path } from "effect"
// Create a custom path implementation
const customPath = Path.make({
sep: "/",
basename: (path: string, suffix?: string) => {
const base = path.split("/").pop() || ""
return suffix && base.endsWith(suffix)
? base.slice(0, -suffix.length)
: base
},
dirname: (path: string) => path.split("/").slice(0, -1).join("/") || "/",
extname: (path: string) => {
const match = path.match(/\.[^.]*$/)
return match ? match[0] : ""
},
format: (pathObject) => {
const dir = pathObject.dir || ""
const name = pathObject.name || ""
const ext = pathObject.ext || ""
return dir ? `${dir}/${name}${ext}` : `${name}${ext}`
},
fromFileUrl: (url: URL) => Effect.succeed(url.pathname),
isAbsolute: (path: string) => path.startsWith("/"),
join: (...paths: ReadonlyArray<string>) => paths.join("/"),
normalize: (path: string) => path.replace(//+/g, "/"),
parse: (path: string) => ({
root: path.startsWith("/") ? "/" : "",
dir: path.split("/").slice(0, -1).join("/") || "/",
base: path.split("/").pop() || "",
ext: path.match(/\.[^.]*$/)?.[0] || "",
name: path.split("/").pop()?.replace(/\.[^.]*$/, "") || ""
}),
relative: (from: string, to: string) => to.replace(from, ""),
resolve: (...pathSegments: ReadonlyArray<string>) => pathSegments.join("/"),
toFileUrl: (path: string) => Effect.succeed(new URL(`file://${path}`)),
toNamespacedPath: (path: string) => path
})
// Provide the path service
const customPathLayer = Layer.succeed(Path.Path)(customPath)
const program = Effect.gen(function*() {
const path = yield* Path.Path
return path.join("home", "user", "file.txt")
})
// Run with custom path implementation
Effect.runSync(Effect.provide(program, customPathLayer)) // => "home/user/file.txt"

Path

interface unstable
Since v4.0.0

Defines the service interface for platform-specific path manipulation.

When to use

Use to depend on path operations through the Effect environment instead of a concrete host path module.

Details

The service exposes operations for joining, normalizing, parsing, formatting, and converting file system paths. URL conversion methods return Effects because invalid file URLs or paths can fail with BadArgument.

resolveWithin(root, input) resolves a relative input beneath root and returns Option.none() when the result would leave the root or when input has its own root (an absolute path, or a Windows drive or UNC prefix). The root itself is allowed. The check is lexical: it does not follow symlinks, so it is not a sandbox on its own. A relative root is resolved against the current working directory, as with resolve.

Signature

interface Path {
readonly "~effect/Path": "~effect/Path";
readonly basename: (path: string, suffix?: string) => string;
readonly dirname: (path: string) => string;
readonly extname: (path: string) => string;
readonly format: (pathObject: Partial<Path.Parsed>) => string;
readonly fromFileUrl: (url: URL) => Effect<string, BadArgument>;
readonly isAbsolute: (path: string) => boolean;
readonly join: (...paths: readonly Array<string>) => string;
readonly normalize: (path: string) => string;
readonly parse: (path: string) => Parsed;
readonly relative: (from: string, to: string) => string;
readonly resolve: (...pathSegments: readonly Array<string>) => string;
readonly resolveWithin: (root: string, input: string) => Option<string>;
readonly sep: string;
readonly toFileUrl: (path: string) => Effect<URL, BadArgument>;
readonly toNamespacedPath: (path: string) => string;
}

Example Using path operations

import { Effect, Option, Path } from "effect"
const program = Effect.gen(function*() {
const path = yield* Path.Path
return {
joined: path.join("home", "user", "documents"),
normalized: path.normalize("./path/../to/file.txt"),
basename: path.basename("/path/to/file.txt"),
dirname: path.dirname("/path/to/file.txt"),
extname: path.extname("file.txt"),
isAbsolute: path.isAbsolute("/absolute/path"),
name: path.parse("/path/to/file.txt").name,
relative: path.relative("/from/path", "/to/path"),
resolved: path.resolve("/base", "relative", "path"),
within: path.resolveWithin("/base", "../outside")
}
})
const result = Effect.runSync(Effect.provide(program, Path.layer))
result.joined // => "home/user/documents"
result.normalized // => "to/file.txt"
result.basename // => "file.txt"
result.dirname // => "/path/to"
result.extname // => ".txt"
result.isAbsolute // => true
result.name // => "file"
result.relative // => "../../to/path"
result.resolved // => "/base/relative/path"
result.within // => Option.none()

Type IDs

TypeId

unstable
Since v4.0.0

Runtime type identifier used to mark implementations of the Path service.

Details

The marker is the exact string stored on Path service implementations. Most code should depend on the Path service instead of inspecting this value directly.

See

  • layer for the built-in POSIX Path service layer

Signature

declare const TypeId: "~effect/Path"