Warning: Effeck is v0. The language will change in major, breaking ways. It is not suitable for production use.

Effeck

A language for writing Effect programs. Specification, 2026-10-16. Runtime: effect@4.0.5.

Effeck is TypeScript syntax in which every function is an Effect. You call functions normally, throw and catch typed errors, and ask for services by name. The compiler infers each function's Effect<A, E, R> and emits the Effect code you would have written by hand, so TypeScript code uses it like any other Effect library.

Effect today (TypeScript)
const welcome = Effect.fn("welcome")(function* (id: string) {
  const users = yield* Users
  const mailer = yield* Mailer
  const user = yield* users.find(id)
  yield* mailer.send(user.email, `Welcome, ${user.name}!`)
  return user.name
})
Effeck
function welcome(id: string) {
  const user = Users.find(id)
  Mailer.send(user.email, `Welcome, ${user.name}!`)
  return user.name
}
// string!UserNotFound | MailError!Users | Mailer

The comment under the Effeck version is not something you write. It is the contract the compiler infers, and what your editor shows when you hover over welcome.

The two functions do the same work, with two differences. Effect.fn("welcome") opens a tracing span on every call; Effeck adds a span only where you ask for one (Chapter 2). And the generated code looks each service up at the call that uses it, so a missing Mailer fails after Users.find has run instead of before.

How to read this document

PartWhat it coversRead it if
I. The language by exampleFunctions, errors, dependency injection, pipelines, resources, concurrency, producers, handlers, TypeScript interop, the standard library, and the questions Effect users ask, each shown next to the Effect code you write todayYou use Effect and want to know what Effeck is like. Start here.
II. The rulesThe precise rules behind Part I: what a call means, how contracts are inferred and checked, which functions compile to plain JavaScriptYou are reviewing the language design
III. The runtimeHow Effeck runs on Effect's fiber runtime: one-shot delimited continuations, ownership, cancellation, and the tests that check themYou care how it executes, or you are reviewing the runtime
IV. The compilerThe fork of the TypeScript compiler, the pipeline, declarations, and editor supportYou will build it
V. DecisionsEvery decision with its reason and evidence, the closed end-to-end build calls, and the experiments that confirm the implementationYou want to check or change a decision
AppendicesThe evidence index, prior art, and every Effect feature mapped to EffeckYou want to check a claim

To learn Effeck by task rather than by rule, start with the user guide. The cheat sheet puts every change beside the Effect code it replaces.

Status. This is the specification. Every rule in it is decided: the owner's decisions and the defaults made to complete the design are logged in docs/design/DECISIONS.md (D1-D60) and collected in Part V, which records the closed end-to-end build calls. D57 and D58 are controversial defaults. The runtime in Part III is a working prototype: 148 tests pass in experiments/. The compiler exists as two prototypes: prototype/esc, on TypeScript's API, compiles 46 example files written from this document, and the Go fork of TypeScript in typescript/ lowers calls by type and infers contracts (Chapter 27). The compiler, spec, runtime, and tooling share one private repository (D60).

Effect to Effeck at a glance

In Effect todayIn EffeckChapter
Effect.gen(function* () { … }), Effect.fn(…)an ordinary function2
yield* effectjust call it: f(x)2
Effect.map, Effect.flatMap, Effect.andThen, Effect.tapplain statements: const x = f(); g(x)2
Effect.fail(e) or return yield* new E()throw new E()3
class E extends Data.TaggedError("E")<{ ... }> {}error E { ... }3
Effect.catchTag("E", h)try { … } catch (e) { … }3
Effect.ensuring(cleanup)finally { … }3
class S extends Context.Service<…>()("key") {}service S { method(): A!E }4
const s = yield* S then yield* s.method()S.method()4
Layer.effect(S, Effect.gen(…))Layer.effect(S) { … }4
program.pipe(Effect.provide(layer))provide layer { program() }4
effect.pipe(Effect.retry(…), Effect.timeout(…))f() |> retry(%, …) |> timeout(%, …)5
Effect.scoped with Effect.acquireReleaseusing x = acquire()6
Effect.all([a, b], { concurrency: 2 })Effect.all([() => a(), () => b()], { concurrency: 2 })7
Effect.forkScoped(effect)fork(() => f()), owned by the enclosing block7
a Stream you build by handa function* producer and for...of8
nothing comparablecontrol Op { ... } and handle9
node:fs, fetch, process.env, child_processFileSystem, HttpClient, Config, ChildProcessSpawner11

Where async, Option, Schema, Stream, testing, and the rest of Effect fit is answered in Chapter 12 and, feature by feature, in Appendix C.