Effect is a TypeScript library for building production-grade software: typed error handling, structured concurrency, resource safety, and observability, all from one composable core.
Why Effect? I read thru this Welcome section in the Effect docs and it describes that TypeScript is excellent at describing your data, but it says almost nothing about your programs: a function’s signature doesn’t tell you what can fail, what dependencies it needs, or whether it can be safely retried, timed out, or interrupted. Effect closes that gap with a single building block: the Effect type, a value that fully describes a program, including its success value, its possible errors, and its requirements.
Traditionally, we would do the following to handle errors in a TS function:
// Type signature doesn't show possible exceptionsconst divide = (a: number, b: number): number => { if (b === 0) { throw new Error("Cannot divide by zero") } return a / b}divide(4, 2) // => 2
but this function’s type signature do not indicate that they can throw exceptions. Now with Effect, you could rewrite this division function as shown below:
In this example, the divide function indicates in its return type Effect<number, Error> that the operation can either succeed with a number or fail with an Error.
┌─── Produces a value of type number │ ┌─── Fails with an Error ▼ ▼Effect<number, Error>
Below is another example, simulating a user retrieval operation:
import { Effect } from "effect"// Define a User typeinterface User { readonly id: number readonly name: string}// A mocked function to simulate fetching a user from a databaseconst getUser = (userId: number): Effect.Effect<User, Error> => { // Normally, you would access a database or API here, but we'll mock it const userDatabase: Record<number, User> = { 1: { id: 1, name: "John Doe" }, 2: { id: 2, name: "Jane Smith" }, } // Check if the user exists in our "database" and return appropriately const user = userDatabase[userId] if (user) { return Effect.succeed(user) } else { return Effect.fail(new Error("User not found")) }}// When executed, this will successfully return the user with id 1const exampleUserEffect = getUser(1)Effect.runSync(exampleUserEffect).name // => "John Doe"
I spent 3+ years studying OSS codebases and wrote 400+ articles on what makes the production-grade. Now I'm putting that into practice differently - instead of writing every fix myself, I run coding agents that do it.
How it works? Register your machine as a Runtime, point it at your repo. Agents pick up issues. write the fix, open the PR. You just review, they execute.