Ref
Stores fiber-safe mutable state inside Effect programs.
A Ref<A> holds one value and exposes reads, writes, and atomic
transformations as effects, so state changes compose with Effect's
concurrency model. This module includes constructors, safe and unsafe reads,
set and get-and-set helpers, update and modify helpers, and conditional
update variants that leave the value unchanged when an Option.none result
is returned.
Constructors
Creates a new Ref with the specified initial value.
When to use
Use to create a Ref for shared mutable state inside an Effect program.
See
- makeUnsafe for synchronous construction outside Effect code
Signature
declare function make<A>(value: A): Effect<Ref<A>>Example
(Creating a ref)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const ref = yield* Ref.make(42) return yield* Ref.get(ref)})
await Effect.runPromise(program) // => 42makeUnsafe
Creates a new Ref with the specified initial value (unsafe version).
When to use
Use when you need immediate synchronous construction and can guarantee
that creating the Ref outside of Effect is safe.
Gotchas
Prefer Ref.make for Effect-wrapped creation in Effect programs.
Signature
declare function makeUnsafe<A>(value: A): Ref<A>Example
(Creating a ref unsafely)
import { Ref } from "effect"
const counter = Ref.makeUnsafe(0)Ref.getUnsafe(counter) // => 0Getters
Gets the current value of the Ref.
When to use
Use to read the current Ref value without changing it.
See
- set for replacing the current value
Signature
declare function get<A>(self: Ref<A>): Effect<A, never, never>Example
(Getting the current value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const ref = yield* Ref.make(42) return yield* Ref.get(ref)})
await Effect.runPromise(program) // => 42Gets the current value of the Ref synchronously (unsafe version).
When to use
Use when you need immediate synchronous access and can guarantee that
reading the Ref outside of Effect is safe.
Gotchas
Prefer Ref.get for Effect-wrapped access in Effect programs.
Signature
declare function getUnsafe<A>(self: Ref<A>): AExample
(Reading a ref unsafely)
import { Ref } from "effect"
const counter = Ref.makeUnsafe(42)Ref.getUnsafe(counter) // => 42Models
A mutable reference that provides atomic read, write, and update operations.
When to use
Use to keep shared mutable state that is read and updated inside Effect programs.
Details
A Ref is a thread-safe mutable reference type for shared state. It supports
simple read and write operations as well as atomic transformations.
See
Signature
interface Ref<in out A> extends Variance<A>, Pipeable { readonly ref: MutableRef<A>;}Example
(Reading and updating a ref)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(0) const value = yield* Ref.get(counter) yield* Ref.update(counter, (n) => n + 1) const newValue = yield* Ref.get(counter) return [value, newValue]})
await Effect.runPromise(program) // => [0, 1]Mutations
Gets the current value of the Ref, sets it to the specified value, and returns the previous value atomically.
When to use
Use to replace a plain Ref value while returning the previous value.
See
- set for setting without returning the previous value
- getAndUpdate for deriving the new value from the previous value
Signature
declare const getAndSet: <A>(value: A) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, value: A) => Effect<A>Example
(Replacing a value atomically)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const ref = yield* Ref.make("initial")
const previous = yield* Ref.getAndSet(ref, "updated") const current = yield* Ref.get(ref) return [previous, current]})
await Effect.runPromise(program) // => ["initial", "updated"]getAndUpdate
Gets the current value of the Ref, updates it with the given function, and returns the previous value atomically.
When to use
Use to derive a new Ref value while returning the previous value.
See
- update for updating without returning the previous value
- updateAndGet for returning the new value instead
Signature
declare const getAndUpdate: <A>(f: (a: A) => A) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, f: (a: A) => A) => Effect<A>Example
(Updating and returning the previous value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(10)
const previous = yield* Ref.getAndUpdate(counter, (n) => n * 2) const current = yield* Ref.get(counter) return [previous, current]})
await Effect.runPromise(program) // => [10, 20]getAndUpdateSome
Gets the current value of the Ref and updates it atomically with the given partial function.
When to use
Use to return the previous Ref value while applying a conditional update.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged. The effect
always returns the value that was in the Ref before the attempted update.
See
- getAndUpdate for always applying an update
- updateSome for conditional updates without returning the previous value
Signature
declare const getAndUpdateSome: <A>(pf: (a: A) => Option<A>) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, pf: (a: A) => Option<A>) => Effect<A>Example
(Conditionally updating and returning the previous value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(5)
const previous1 = yield* Ref.getAndUpdateSome( counter, (n) => n > 3 ? Option.some(n * 2) : Option.none() ) const current1 = yield* Ref.get(counter) const previous2 = yield* Ref.getAndUpdateSome( counter, (n) => n < 3 ? Option.some(n * 2) : Option.none() ) const current2 = yield* Ref.get(counter) return [previous1, current1, previous2, current2]})
await Effect.runPromise(program) // => [5, 10, 10, 10]Modifies the value of the Ref atomically using the given function.
When to use
Use to compute both a separate return value and the next stored Ref value
in one atomic update.
Details
The function receives the current value and returns a tuple of
[result, newValue]. The Ref is updated with newValue, and result is
returned by the effect.
See
- updateAndGet for returning the new stored value
- modifySome for optionally updating while returning a separate result
Signature
declare const modify: <A, B>(f: (a: A) => readonly [B, A]) => (self: Ref<A>) => Effect<B> & <A, B>(self: Ref<A>, f: (a: A) => readonly [B, A]) => Effect<B>Example
(Modifying a value atomically)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(10)
const result = yield* Ref.modify(counter, (n) => [ `Previous value was ${n}`, n * 2 ]) const current = yield* Ref.get(counter) return [result, current]})
const program2 = Effect.gen(function*() { const state = yield* Ref.make({ count: 0, total: 0 }) return yield* Ref.modify(state, (s) => [ s.count, { count: s.count + 1, total: s.total + s.count + 1 } ])})
await Effect.runPromise(program) // => ["Previous value was 10", 20]await Effect.runPromise(program2) // => 0modifySome
Computes a result atomically and optionally updates the value of the Ref.
When to use
Use to compute a return value while optionally updating a plain Ref.
Details
The callback receives the current value and returns [result, nextValue],
where nextValue is an Option. If nextValue is Option.some(value),
the Ref is updated to value; if it is Option.none(), the Ref is left
unchanged. The returned effect always succeeds with result.
See
- modify for always storing a new value
- updateSome for optional updates without a separate return value
Signature
declare const modifySome: { <B, A>(pf: (a: A) => readonly [B, Option<A>]): (self: Ref<A>) => Effect<B>; <A, B>(self: Ref<A>, pf: (a: A) => readonly [B, Option<A>]): Effect<B>;}Example
(Conditionally modifying a value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(5)
const result1 = yield* Ref.modifySome( counter, (n) => n > 3 ? [`incremented ${n}`, Option.some(n + 10)] : ["no change", Option.none()] ) const current1 = yield* Ref.get(counter) const result2 = yield* Ref.modifySome( counter, (n) => n < 10 ? [`decremented ${n}`, Option.some(n - 5)] : ["no change", Option.none()] ) const current2 = yield* Ref.get(counter) return [result1, current1, result2, current2]})
await Effect.runPromise(program) // => ["incremented 5", 15, "no change", 15]Sets the value of the Ref to the specified value.
When to use
Use to replace the current Ref value with a known value.
See
Signature
declare const set: <A>(value: A) => (self: Ref<A>) => Effect<void> & <A>(self: Ref<A>, value: A) => Effect<void>Example
(Setting a value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const ref = yield* Ref.make(0) yield* Ref.set(ref, 42) return yield* Ref.get(ref)})
const program2 = Effect.gen(function*() { const ref = yield* Ref.make(0) yield* Ref.set(ref, 100) return yield* Ref.get(ref)})
await Effect.runPromise(program) // => 42await Effect.runPromise(program2) // => 100Sets the value of the Ref atomically to the specified value and returns the new value.
When to use
Use when you want to set a Ref value and immediately get it back in one
atomic operation.
Signature
declare const setAndGet: <A>(value: A) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, value: A) => Effect<A>Example
(Setting and returning the new value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const ref = yield* Ref.make(10)
const newValue = yield* Ref.setAndGet(ref, 42) const current = yield* Ref.get(ref) return [newValue, current]})
const program2 = Effect.gen(function*() { const counter = yield* Ref.make(0) return yield* Ref.setAndGet(counter, 20)})
await Effect.runPromise(program) // => [42, 42]await Effect.runPromise(program2) // => 20Updates the value of the Ref atomically using the given function.
When to use
Use to apply a Ref state transition without returning a value.
See
- updateAndGet for returning the new value
- getAndUpdate for returning the previous value
Signature
declare const update: <A>(f: (a: A) => A) => (self: Ref<A>) => Effect<void> & <A>(self: Ref<A>, f: (a: A) => A) => Effect<void>Example
(Updating a value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(5)
yield* Ref.update(counter, (n) => n * 2) return yield* Ref.get(counter)})
const program2 = Effect.gen(function*() { const counter = yield* Ref.make(5) yield* Ref.update(counter, (n: number) => n + 10) return yield* Ref.get(counter)})
await Effect.runPromise(program) // => 10await Effect.runPromise(program2) // => 15updateAndGet
Updates the value of the Ref atomically using the given function and returns the new value.
When to use
Use to apply a Ref state transition and return the new stored value.
See
- update for updating without returning the new value
- getAndUpdate for returning the previous value instead
Signature
declare const updateAndGet: <A>(f: (a: A) => A) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, f: (a: A) => A) => Effect<A>Example
(Updating and returning the new value)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(5)
const newValue = yield* Ref.updateAndGet(counter, (n) => n * 3) const current = yield* Ref.get(counter) return [newValue, current]})
await Effect.runPromise(program) // => [15, 15]updateSome
Updates the value of the Ref atomically using the given partial function.
When to use
Use to apply a conditional Ref update without returning a value.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged.
See
- update for always applying an update
- updateSomeAndGet for returning the resulting current value
Signature
declare const updateSome: <A>(f: (a: A) => Option<A>) => (self: Ref<A>) => Effect<void> & <A>(self: Ref<A>, f: (a: A) => Option<A>) => Effect<void>Example
(Conditionally updating a value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(5)
yield* Ref.updateSome( counter, (n) => n % 2 === 0 ? Option.some(n * 2) : Option.none() ) const before = yield* Ref.get(counter) yield* Ref.set(counter, 6) yield* Ref.updateSome( counter, (n) => n % 2 === 0 ? Option.some(n * 2) : Option.none() ) const after = yield* Ref.get(counter) return [before, after]})
await Effect.runPromise(program) // => [5, 12]updateSomeAndGet
Updates the value of the Ref atomically using the given partial function and returns the current value.
When to use
Use to apply a conditional Ref update and return the resulting current
value.
Details
If the partial function returns Option.some, the Ref is updated with the
new value. If it returns Option.none, the Ref is left unchanged. The effect
returns the current value of the Ref after the potential update.
See
- updateSome for conditional updates without returning a value
- updateAndGet for always updating and returning the new value
Signature
declare const updateSomeAndGet: <A>(pf: (a: A) => Option<A>) => (self: Ref<A>) => Effect<A> & <A>(self: Ref<A>, pf: (a: A) => Option<A>) => Effect<A>Example
(Conditionally updating and returning the current value)
import { Effect, Option, Ref } from "effect"
const program = Effect.gen(function*() { const counter = yield* Ref.make(10)
const result1 = yield* Ref.updateSomeAndGet( counter, (n) => n > 5 ? Option.some(n / 2) : Option.none() ) const result2 = yield* Ref.updateSomeAndGet( counter, (n) => n > 5 ? Option.some(n / 2) : Option.none() ) return [result1, result2]})
await Effect.runPromise(program) // => [5, 5]