Skip to content
LogoLogo

Path

Path provides Effect's platform-specific path service to VibeLang. Use it to join, split, normalize, and convert paths without hard-coding host separators or importing a native path module.

Requesting the path service

// run: provide Path.layer { Console.log(pathSeparator()) }
function pathSeparator() {
  const path = Effect.service(Path.Path)
  return path.sep
}
// string!!Path.Path
// Output: /

Path is the module and Path.Path is its service key. Effect.service obtains the implementation from the current environment. Reading sep returns that implementation's path separator.

Manipulating paths portably

// run: provide Path.layer { Console.log(JSON.stringify(describeReport())) }
function describeReport() {
  const path = Effect.service(Path.Path)
  const joined = path.join("reports", "weekly.txt")
  const normalized = path.normalize("reports/./draft/../weekly.txt")
  const parsed = path.parse(joined)
  return {
    joined,
    normalized,
    base: path.basename(joined),
    directory: path.dirname(joined),
    extension: path.extname(joined),
    absolute: path.isAbsolute(joined),
    rebuilt: path.format(parsed)
  }
}
// Output: {"joined":"reports/weekly.txt","normalized":"reports/weekly.txt","base":"weekly.txt","directory":"reports","extension":".txt","absolute":false,"rebuilt":"reports/weekly.txt"}

Most Path methods are plain synchronous TypeScript functions. Effect's own packages are trusted, so call these methods directly; exceptions escaping into Effect code are defects, which its catch does not handle. A plain-contract function keeps JavaScript catch and can recover the exception as unknown (D260). Calling a member through the key, such as Path.Path.join("reports", "weekly.txt"), looks up the service and adds Path.Path to R even though the member returns a string.

OperationResult
basename, dirname, extnameFile name, directory, or extension
join, normalizeA combined or simplified path
parse, formatStructured path components or their string form
isAbsoluteWhether a path has an absolute root
relative, resolveA relative relationship or an absolute resolution
sepThe implementation's separator
toNamespacedPathA Windows namespace path where applicable
toFileUrl, fromFileUrlEffectful file-URL conversion
// run: provide Path.layer { Console.log(asFileUrl("/reports/weekly.txt")) }
function asFileUrl(file: string) {
  const path = Effect.service(Path.Path)
  const absolute = path.resolve(file)
  const url = path.toFileUrl(absolute)
  return path.fromFileUrl(url)
}
// Output: /reports/weekly.txt

URL conversions return Effects and run directly when called, reporting BadArgument on invalid input. Path string operations are lexical: normalizing or resolving a path does not check that a file exists. Use FileSystem when filesystem state matters.

Supplying a platform path implementation

// main.vibe
import { NodeRuntime, NodeServices } from "@effect/platform-node"
 
function main() {
  const output = Path.Path.join("reports", "weekly.txt")
  Console.log(output)
}
 
NodeRuntime.runMain(() => Effect.provide(() => main(), NodeServices.layer))
// Output: reports/weekly.txt

The Node service bundle supplies host path behavior. Path.layer supplies the built-in POSIX implementation for programs that intentionally use POSIX paths, including deterministic tests. Use Bun's service bundle when the rest of the application runs against Bun platform services.

Coming from Effect

Effect-returning methods run directly; synchronous methods from Effect's trusted packages return plain values. Both forms look up the service when called through its key, so both add the service to R. Value members are read from the implementation, for example Path.Path().sep.


The matching Effect page: effect.website/docs/v4/platform/path