MutableRef
A MutableRef<A> is a small synchronous container for mutable state. It holds one
current value of type A, exposes it through .current, and offers pipeable
helpers for reading, replacing, and transforming the value in place.
Unlike Ref, every MutableRef operation is an
ordinary synchronous call — get returns the value directly, set/update
return the reference, and getAndSet/updateAndGet return the old or new value.
There is no Effect wrapping and nothing to yield*.
import { MutableRef } from "effect"
// `make` returns the reference directly — no Effect, no yield*.const counter = MutableRef.make(0)
// Read with `get` (or just `.current`).MutableRef.get(counter) // => 0
// `update` mutates in place and returns the same reference.MutableRef.update(counter, (n) => n + 1)MutableRef.get(counter) // => 1
// `set` replaces the value and also returns the reference.MutableRef.set(counter, 10)
// `.current` is a plain readable/writable field.counter.current // => 10counter.current = 20counter.current // => 20When to use MutableRef (vs Ref)
Section titled “When to use MutableRef (vs Ref)”Reach for MutableRef when state is local, single-fiber, and synchronous —
a tight loop, a builder accumulating a result, an Inspectable that
tracks a running count, or any place where you would otherwise reach for a plain
let but want a stable, pipeable handle you can pass around.
The moment state is shared across fibers, or you need updates to participate
in Effect composition, interruption, or fiber coordination, switch to
Ref or
SynchronizedRef. MutableRef updates are
plain imperative mutations: they are not atomic with respect to concurrent
fibers and do not return effects.
A typical use is an accumulator inside a synchronous loop:
import { MutableRef } from "effect"
const sumTo = (n: number): number => { const total = MutableRef.make(0) for (let i = 1; i <= n; i++) { MutableRef.update(total, (t) => t + i) } return MutableRef.get(total)}
sumTo(5) // => 15Naming conventions
Section titled “Naming conventions”Two consistent patterns run through the API:
- The
getAnd*helpers (getAndSet,getAndUpdate,getAndIncrement,getAndDecrement) return the previous value. - The
*AndGethelpers (setAndGet,updateAndGet,incrementAndGet,decrementAndGet) return the new value.
Helpers that mutate without surfacing a value (set, update, increment,
decrement, toggle) return the MutableRef itself, so they can be chained or
piped.
Most binary operators are dual: you can call them data-first
(MutableRef.set(ref, value)) or data-last for piping
(MutableRef.set(value)). MutableRef also implements
Pipeable and Inspectable, so it can be used with
.pipe(...) and prints cleanly via JSON.stringify / Inspectable.
Reference
Section titled “Reference”Creates a new MutableRef initialized with the given value. @category constructors
import { MutableRef } from "effect"
const ref = MutableRef.make(42)MutableRef.get(ref) // => 42
const config = MutableRef.make({ debug: false, timeout: 5000 })MutableRef.get(config) // => { debug: false, timeout: 5000 }Reads the current value without mutating the reference. Equivalent to reading
.current. @category general
import { MutableRef } from "effect"
const ref = MutableRef.make("hello")MutableRef.get(ref) // => "hello"ref.current // => "hello"Replaces the current value and returns the reference (for chaining). Dual:
set(ref, value) or set(value). @category general
import { MutableRef } from "effect"
const ref = MutableRef.make("initial")
const same = MutableRef.set(ref, "updated")same === ref // => trueMutableRef.get(ref) // => "updated"
// Pipeable (data-last) formref.pipe(MutableRef.set("final"))MutableRef.get(ref) // => "final"setAndGet
Section titled “setAndGet”Replaces the current value and returns the new value. Dual. @category general
import { MutableRef } from "effect"
const ref = MutableRef.make("old")MutableRef.setAndGet(ref, "new") // => "new"MutableRef.get(ref) // => "new"getAndSet
Section titled “getAndSet”Replaces the current value and returns the previous value. Dual.
@category general
import { MutableRef } from "effect"
const ref = MutableRef.make("old")MutableRef.getAndSet(ref, "new") // => "old"MutableRef.get(ref) // => "new"update
Section titled “update”Applies f to the current value, stores the result, and returns the
reference (for chaining). Dual: update(ref, f) or update(f).
@category general
import { MutableRef } from "effect"
const counter = MutableRef.make(5)
const same = MutableRef.update(counter, (n) => n + 1)same === counter // => trueMutableRef.get(counter) // => 6
// Updates do not clone — return a new value to avoid mutating in placeconst user = MutableRef.make({ name: "Alice", age: 30 })MutableRef.update(user, (u) => ({ ...u, age: u.age + 1 }))MutableRef.get(user) // => { name: "Alice", age: 31 }updateAndGet
Section titled “updateAndGet”Applies f to the current value, stores the result, and returns the new
value. Dual. @category general
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.updateAndGet(counter, (n) => n * 2) // => 10MutableRef.get(counter) // => 10getAndUpdate
Section titled “getAndUpdate”Applies f to the current value, stores the result, and returns the
previous value. Dual. @category general
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.getAndUpdate(counter, (n) => n + 1) // => 5MutableRef.get(counter) // => 6compareAndSet
Section titled “compareAndSet”Sets the value to newValue only if the current value equals oldValue,
returning true if it swapped and false otherwise. Comparison uses Effect’s
Equal semantics, not only JavaScript reference equality. Dual:
compareAndSet(ref, oldValue, newValue) or compareAndSet(oldValue, newValue).
@category general
import { MutableRef } from "effect"
const ref = MutableRef.make("initial")
// Succeeds: current value matches the expected `oldValue`MutableRef.compareAndSet(ref, "initial", "updated") // => trueMutableRef.get(ref) // => "updated"
// Fails: current value no longer matches — no change is madeMutableRef.compareAndSet(ref, "initial", "other") // => falseMutableRef.get(ref) // => "updated"increment
Section titled “increment”Adds 1 to a numeric reference in place and returns the reference.
@category numeric
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.increment(counter)MutableRef.get(counter) // => 6decrement
Section titled “decrement”Subtracts 1 from a numeric reference in place and returns the reference.
@category numeric
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.decrement(counter)MutableRef.get(counter) // => 4incrementAndGet
Section titled “incrementAndGet”Adds 1 to a numeric reference and returns the new value (pre-increment,
like ++i). @category numeric
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.incrementAndGet(counter) // => 6decrementAndGet
Section titled “decrementAndGet”Subtracts 1 from a numeric reference and returns the new value.
@category numeric
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.decrementAndGet(counter) // => 4getAndIncrement
Section titled “getAndIncrement”Adds 1 to a numeric reference and returns the previous value
(post-increment, like i++). Handy for ID generation. @category numeric
import { MutableRef } from "effect"
const ids = MutableRef.make(0)MutableRef.getAndIncrement(ids) // => 0MutableRef.getAndIncrement(ids) // => 1MutableRef.get(ids) // => 2getAndDecrement
Section titled “getAndDecrement”Subtracts 1 from a numeric reference and returns the previous value.
@category numeric
import { MutableRef } from "effect"
const counter = MutableRef.make(5)MutableRef.getAndDecrement(counter) // => 5MutableRef.get(counter) // => 4toggle
Section titled “toggle”Flips a boolean reference between true and false in place and returns the
reference. @category boolean
import { MutableRef } from "effect"
const flag = MutableRef.make(false)MutableRef.toggle(flag)MutableRef.get(flag) // => trueMutableRef.toggle(flag)MutableRef.get(flag) // => false