Skip to content

FileSystem

The @effect/platform/FileSystem module provides a set of operations for reading and writing from/to the file system.

The module provides a single FileSystem tag, which acts as the gateway for interacting with the filesystem.

Example (Accessing File System Operations)

import {
import FileSystem
FileSystem
} from "@effect/platform"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, FileSystem.FileSystem>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<FileSystem.FileSystem, FileSystem.FileSystem>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Tag<FileSystem.FileSystem, FileSystem.FileSystem>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const fs: FileSystem.FileSystem
fs
= yield*
import FileSystem
FileSystem
.
const FileSystem: Tag<FileSystem.FileSystem, FileSystem.FileSystem>

@since1.0.0

@since1.0.0

FileSystem
// Use `fs` to perform file system operations
})

The FileSystem interface includes the following operations:

OperationDescription
accessCheck if a file can be accessed. You can optionally specify the level of access to check for.
copyCopy a file or directory from fromPath to toPath. Equivalent to cp -r.
copyFileCopy a file from fromPath to toPath.
chmodChange the permissions of a file.
chownChange the owner and group of a file.
existsCheck if a path exists.
linkCreate a hard link from fromPath to toPath.
makeDirectoryCreate a directory at path. You can optionally specify the mode and whether to recursively create nested directories.
makeTempDirectoryCreate a temporary directory. By default, the directory will be created inside the system’s default temporary directory.
makeTempDirectoryScopedCreate a temporary directory inside a scope. Functionally equivalent to makeTempDirectory, but the directory will be automatically deleted when the scope is closed.
makeTempFileCreate a temporary file. The directory creation is functionally equivalent to makeTempDirectory. The file name will be a randomly generated string.
makeTempFileScopedCreate a temporary file inside a scope. Functionally equivalent to makeTempFile, but the file will be automatically deleted when the scope is closed.
openOpen a file at path with the specified options. The file handle will be automatically closed when the scope is closed.
readDirectoryList the contents of a directory. You can recursively list the contents of nested directories by setting the recursive option.
readFileRead the contents of a file.
readFileStringRead the contents of a file as a string.
readLinkRead the destination of a symbolic link.
realPathResolve a path to its canonicalized absolute pathname.
removeRemove a file or directory. By setting the recursive option to true, you can recursively remove nested directories.
renameRename a file or directory.
sinkCreate a writable Sink for the specified path.
statGet information about a file at path.
streamCreate a readable Stream for the specified path.
symlinkCreate a symbolic link from fromPath to toPath.
truncateTruncate a file to a specified length. If the length is not specified, the file will be truncated to length 0.
utimesChange the file system timestamps of the file at path.
watchWatch a directory or file for changes.
writeFileWrite data to a file at path.
writeFileStringWrite a string to a file at path.

Example (Reading a File as a String)

import {
import FileSystem
FileSystem
} from "@effect/platform"
import {
import NodeContext
NodeContext
,
import NodeRuntime
NodeRuntime
} from "@effect/platform-node"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, PlatformError, FileSystem.FileSystem>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<FileSystem.FileSystem, FileSystem.FileSystem>> | YieldWrap<Effect.Effect<string, PlatformError, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const fs: FileSystem.FileSystem
fs
= yield*
import FileSystem
FileSystem
.
const FileSystem: Tag<FileSystem.FileSystem, FileSystem.FileSystem>

@since1.0.0

@since1.0.0

FileSystem
// Reading the content of the same file where this code is written
const
const content: string
content
= yield*
const fs: FileSystem.FileSystem
fs
.
FileSystem.readFileString: (path: string, encoding?: string) => Effect.Effect<string, PlatformError>

Read the contents of a file.

readFileString
("./index.ts", "utf8")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
const content: string
content
)
})
// Provide the necessary context and run the program
import NodeRuntime
NodeRuntime
.
const runMain: RunMain
<PlatformError, void>(effect: Effect.Effect<void, PlatformError, never>, options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly disablePrettyLogger?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}) => void (+1 overload)
runMain
(
const program: Effect.Effect<void, PlatformError, FileSystem.FileSystem>
program
.
Pipeable.pipe<Effect.Effect<void, PlatformError, FileSystem.FileSystem>, Effect.Effect<void, PlatformError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <NodeContext.NodeContext, never, never>(layer: Layer<NodeContext.NodeContext, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+9 overloads)

Provides the necessary Layers to an effect, removing its dependency on the environment.

You can pass multiple layers, a Context, Runtime, or ManagedRuntime to the effect.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import NodeContext
NodeContext
.
const layer: Layer<NodeContext.NodeContext, never, never>

@since1.0.0

layer
)))