Skip to content
LogoLogo

VIP-6: Effect's functions are globals

Status: accepted by Will, 2026-10-28.

Decision

effect function load(q) {
  const r = try tryPromise((signal) => queryDb(q, { signal }))   // Effect.tryPromise
  const n = try sync(() => Date.now())                           // Effect.sync
  try retry(tryPromise(() => queryDb(q)), policy)
  try sleep("1 second")
  const d = try Effect.try(() => JSON.parse(s))                  // `try` is a reserved word, so it stays Effect.try
}
  • Every export of Effect's Effect module is a global variable in a .vibe file: retry, sleep, log, all, race, tryPromise, sync, callback, map, and so on. A local declaration or import shadows one, as with any global.
  • An option in tsconfig.json turns the globals off (VIP-14: "like before this should be configurable in the tsconfig.json").
  • A name that clashes is not a global, and is used as Effect.x instead. A name clashes if it is:
    • a reserved word: try, catch, void, let;
    • a JavaScript global: undefined;
    • a VibeLang keyword.
  • If a later VIP adds a keyword with the same name as an Effect export, the global is removed. That may happen to match, when, service and provide.
  • No language feature wraps TypeScript into an Effect. You use Effect's own functions (tryPromise, sync, callback, Effect.try), and their arrows capture locals as in Effect TS.

Corrected 2026-10-29: the example calls queryDb, a Promise-returning function imported from a .ts module, because VIP-33 forbids platform calls such as fetch anywhere in a .vibe file.

Prior art

Rust's prelude, Elixir's Kernel, Kotlin's top-level launch and delay, Python's builtins.

Will's words

"We should have a VIP regarding global variables where we make Effect.* global meaning we don't even need a language feature it can just be existing effect syntax for wrapping typescript"

"Ok these are global varaibles. There should be a config option to turn off globals. Anything that clashes must be accessed via Effect.* instead of globally if it clashes with either a javascript global or it clashes with a keyword we end up adding. If we add the keyword in future we will also remove it (like in case of provide and service)"

Footnote: old VibeLang

Old VibeLang is a reference only; nothing in it is part of the language unless a VIP adds it. For implementers, this VIP replaces:

  • D151's hand-picked list of prefix-free functions, widened here to every Effect export.
  • D148's hatches (sync, try, callback as special prelude forms) and D229's no-capture rule.

VIP-14 decides which Effect modules are in scope without an import, with its configuration and precedence rules. Historical D146 supplies no independent authority.