platform
Effect Platform
Overview
@effect/platform provides cross-platform abstractions for:
- HTTP Client - Make HTTP requests
- HTTP Server - Build HTTP servers
- FileSystem - File operations
- KeyValueStore - Persistent storage
- Terminal - CLI interactions
- Worker - Background workers
HTTP Client
Installation
npm install @effect/platform
# For Node.js:
npm install @effect/platform-node
# For Bun:
npm install @effect/platform-bun
Basic Requests
import { HttpClient } from "@effect/platform";
import { NodeHttpClient } from "@effect/platform-node";
import { Effect } from "effect";
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
// GET request
const response = yield* client.get("https://api.example.com/users");
const data = yield* response.json;
return data;
}).pipe(Effect.provide(NodeHttpClient.layer));
Request Configuration
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
// POST with body
const response = yield* client.post("https://api.example.com/users", {
body: HttpClientRequest.jsonBody({ name: "Alice", email: "alice@example.com" }),
});
// With headers
const response = yield* client.get("https://api.example.com/protected", {
headers: { Authorization: "Bearer token123" },
});
// With timeout
const response = yield* client.get("https://api.example.com/slow").pipe(Effect.timeout("5 seconds"));
});
Response Handling
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
const response = yield* client.get("https://api.example.com/data");
// Parse as JSON
const json = yield* response.json;
// Parse as text
const text = yield* response.text;
// Get status
const status = response.status;
// Get headers
const contentType = response.headers["content-type"];
});
Schema Validation
import { HttpClient, HttpClientResponse } from "@effect/platform";
import { Schema } from "effect";
const User = Schema.Struct({
id: Schema.Number,
name: Schema.String,
email: Schema.String,
});
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
const response = yield* client.get("https://api.example.com/users/1");
// Validate response with schema
const user = yield* HttpClientResponse.schemaBodyJson(User)(response);
return user;
});
HTTP Server
Basic Server
import { HttpServer, HttpServerResponse } from "@effect/platform";
import { NodeHttpServer } from "@effect/platform-node";
import { Effect, Layer } from "effect";
import { createServer } from "node:http";
const app = HttpServer.router.empty.pipe(
HttpServer.router.get("/", HttpServerResponse.text("Hello, World!")),
HttpServer.router.get(
"/users",
HttpServerResponse.json([
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]),
),
);
const ServerLive = NodeHttpServer.layer(createServer, { port: 3000 });
const program = Effect.gen(function* () {
yield* Effect.log("Server starting on port 3000");
yield* Effect.never; // Keep running
}).pipe(Effect.provide(HttpServer.router.Live(app)), Effect.provide(ServerLive));
Route Parameters
const app = HttpServer.router.empty.pipe(
HttpServer.router.get(
"/users/:id",
Effect.gen(function* () {
const params = yield* HttpServer.router.params;
const id = params.id;
return HttpServerResponse.json({ id, name: "User " + id });
}),
),
);
Request Body
import { HttpServerRequest } from "@effect/platform";
const app = HttpServer.router.empty.pipe(
HttpServer.router.post(
"/users",
Effect.gen(function* () {
const request = yield* HttpServerRequest.HttpServerRequest;
const body = yield* request.json;
// Or with schema validation
const validated = yield* HttpServerRequest.schemaBodyJson(CreateUser)(request);
return HttpServerResponse.json({ created: true, user: validated });
}),
),
);
FileSystem
Reading Files
import { FileSystem } from "@effect/platform";
import { NodeFileSystem } from "@effect/platform-node";
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const content = yield* fs.readFileString("./config.json");
const bytes = yield* fs.readFile("./image.png");
const exists = yield* fs.exists("./file.txt");
}).pipe(Effect.provide(NodeFileSystem.layer));
Writing Files
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
yield* fs.writeFileString("./output.txt", "Hello, World!");
yield* fs.writeFile("./data.bin", new Uint8Array([1, 2, 3]));
yield* fs.appendFileString("./log.txt", "New log entry\n");
});
Directory Operations
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
yield* fs.makeDirectory("./new-dir", { recursive: true });
const files = yield* fs.readDirectory("./src");
yield* fs.remove("./temp", { recursive: true });
yield* fs.copy("./source.txt", "./dest.txt");
yield* fs.rename("./old.txt", "./new.txt");
});
File Info
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const stat = yield* fs.stat("./file.txt");
console.log({
size: stat.size,
isFile: stat.type === "File",
isDirectory: stat.type === "Directory",
modified: stat.mtime,
});
});
KeyValueStore
Persistent key-value storage:
import { KeyValueStore } from "@effect/platform";
import { NodeKeyValueStore } from "@effect/platform-node";
const program = Effect.gen(function* () {
const store = yield* KeyValueStore.KeyValueStore;
yield* store.set("user:1", JSON.stringify({ name: "Alice" }));
const value = yield* store.get("user:1");
yield* store.remove("user:1");
const exists = yield* store.has("user:1");
}).pipe(Effect.provide(NodeKeyValueStore.layerFileSystem("./data")));
Terminal
CLI interactions:
import { Terminal } from "@effect/platform";
import { NodeTerminal } from "@effect/platform-node";
const program = Effect.gen(function* () {
const terminal = yield* Terminal.Terminal;
const name = yield* terminal.readLine;
yield* terminal.display(`Hello, ${name}!`);
}).pipe(Effect.provide(NodeTerminal.layer));
Complete Example: REST API
import { HttpServer, HttpServerResponse, HttpServerRequest } from "@effect/platform";
import { NodeHttpServer } from "@effect/platform-node";
import { Effect, Layer, Schema } from "effect";
import { createServer } from "node:http";
// Schemas
const CreateUser = Schema.Struct({
name: Schema.String,
email: Schema.String,
});
const User = Schema.Struct({
id: Schema.Number,
name: Schema.String,
email: Schema.String,
});
// In-memory store
let users: Schema.Schema.Type<typeof User>[] = [];
let nextId = 1;
// Routes
const app = HttpServer.router.empty.pipe(
HttpServer.router.get("/users", HttpServerResponse.json(users)),
HttpServer.router.post(
"/users",
Effect.gen(function* () {
const body = yield* HttpServerRequest.schemaBodyJson(CreateUser);
const user = { id: nextId++, ...body };
users.push(user);
return HttpServerResponse.json(user, { status: 201 });
}),
),
HttpServer.router.get(
"/users/:id",
Effect.gen(function* () {
const { id } = yield* HttpServer.router.params;
const user = users.find((u) => u.id === parseInt(id));
return user ? HttpServerResponse.json(user) : HttpServerResponse.json({ error: "Not found" }, { status: 404 });
}),
),
);
// Server
const ServerLive = NodeHttpServer.layer(createServer, { port: 3000 });
const main = HttpServer.serve(app).pipe(Effect.provide(ServerLive), Effect.catchAllCause(Effect.logError));
Effect.runPromise(main);
Best Practices
- Use Schema validation - Validate all external data
- Provide platform layers - NodeHttpClient.layer, etc.
- Handle errors - Network failures, file not found, etc.
- Use Effect.scoped for resources - Files, connections
- Configure timeouts - Prevent hanging requests
Additional Resources
For comprehensive platform documentation, consult ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt.
Search for these sections:
- "HTTP Client" for making requests
- "HTTP Server" for building servers
- "FileSystem" for file operations
- "KeyValueStore" for persistent storage
- "Terminal" for CLI interactions
More from andrueandersoncs/claude-skill-effect-ts
schema
This skill should be used when the user asks about "Effect Schema", "Schema.Struct", "Schema.decodeUnknown", "data validation", "parsing", "Schema.transform", "Schema filters", "Schema annotations", "JSON Schema", "Schema.Class", "Schema branded types", "encoding", "decoding", "Schema.parseJson", or needs to understand how Effect handles data validation and transformation.
13testing
This skill should be used when the user asks about "Effect testing", "@effect/vitest", "it.effect", "it.live", "it.scoped", "it.layer", "it.prop", "Schema Arbitrary", "property-based testing", "fast-check", "TestClock", "testing effects", "mocking services", "test layers", "TestContext", "Effect.provide test", "time testing", "Effect test utilities", "unit testing Effect", "generating test data", "flakyTest", "test coverage", "100% coverage", "service testing", "test doubles", "mock services", or needs to understand how to test Effect-based code.
13traits
This skill should be used when the user asks about "Effect Equal", "Effect Hash", "Equivalence", "Order", "structural equality", "custom equality", "comparing objects", "sorting", "Equal.equals", "Hash.hash", "Equivalence.make", "Order.lessThan", "comparable types", or needs to understand how Effect handles equality, hashing, and ordering of values.
12configuration
This skill should be used when the user asks about "Effect Config", "environment variables", "configuration management", "Config.string", "Config.number", "ConfigProvider", "Config.nested", "Config.withDefault", "Config.redacted", "sensitive values", "config validation", "loading config from JSON", "config schema", or needs to understand how Effect handles application configuration.
12concurrency
This skill should be used when the user asks about "Effect concurrency", "fibers", "Fiber", "forking", "Effect.fork", "Effect.forkDaemon", "parallel execution", "Effect.all concurrency", "Deferred", "Queue", "PubSub", "Semaphore", "Latch", "fiber interruption", "Effect.race", "Effect.raceAll", "concurrent effects", or needs to understand how Effect handles parallel and concurrent execution.
11observability
This skill should be used when the user asks about "Effect logging", "Effect.log", "Effect metrics", "Effect tracing", "spans", "telemetry", "Metric.counter", "Metric.gauge", "Metric.histogram", "OpenTelemetry", "structured logging", "log levels", "Effect.logDebug", "Effect.logInfo", "Effect.logWarning", "Effect.logError", or needs to understand how Effect handles logging, metrics, and distributed tracing.
10