Skip to main content
The Scope module provides resource management for Effect workflows. A Scope tracks finalizers and ensures they run when the scope closes.

Types

Scope

interface Scope
Represents a scope that manages finalizers and can fork child scopes.
strategy
ExecutionStrategy.ExecutionStrategy
The execution strategy for running finalizers

CloseableScope

interface CloseableScope extends Scope
A scope that can be explicitly closed with a specified exit value.

Scope.Finalizer

type Finalizer = (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>
A finalizer function that receives an Exit value and returns an effect.
exit
Exit.Exit<unknown, unknown>
required
The exit value indicating how the scope closed
return
Effect.Effect<void>
An effect performing cleanup

Tag

Scope

A tag representing the current Scope in the environment.
const Scope: Context.Tag<Scope, Scope>
return
Context.Tag<Scope, Scope>
The scope service tag
import { Effect, Scope } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope
  // Use the scope
})

Constructors

make

Creates a new closeable scope.
const make: (
  executionStrategy?: ExecutionStrategy.ExecutionStrategy
) => Effect.Effect<CloseableScope>
executionStrategy
ExecutionStrategy.ExecutionStrategy
How finalizers should execute (defaults to sequential)
return
Effect.Effect<CloseableScope>
An effect that creates a new scope
import { Scope, Effect } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope.make()
  // Add finalizers to scope
  // ...
  // Close when done
  yield* Scope.close(scope, Exit.succeed(void 0))
})

Operations

addFinalizer

Adds a finalizer to a scope. The finalizer runs when the scope closes.
const addFinalizer: (
  self: Scope,
  finalizer: Effect.Effect<unknown>
) => Effect.Effect<void>
self
Scope
required
The scope to add to
finalizer
Effect.Effect<unknown>
required
The cleanup effect to run on close
return
Effect.Effect<void>
An effect that registers the finalizer
import { Scope, Effect, Console } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope
  
  yield* Scope.addFinalizer(
    scope,
    Console.log("Cleaning up!")
  )
  
  // When scope closes, "Cleaning up!" will be logged
})
Use addFinalizer when the finalizer doesn’t need to know the exit value. For exit-aware finalizers, use addFinalizerExit.

addFinalizerExit

Adds a finalizer that receives the exit value when the scope closes.
const addFinalizerExit: (
  self: Scope,
  finalizer: Scope.Finalizer
) => Effect.Effect<void>
self
Scope
required
The scope to add to
finalizer
Scope.Finalizer
required
A function receiving the exit value
return
Effect.Effect<void>
An effect that registers the finalizer
import { Scope, Effect, Exit, Console } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope
  
  yield* Scope.addFinalizerExit(
    scope,
    (exit) => Exit.match(exit, {
      onSuccess: () => Console.log("Success cleanup"),
      onFailure: (cause) => Console.log("Failure cleanup")
    })
  )
})

close

Closes a scope with the specified exit value, running all finalizers.
const close: (
  self: CloseableScope,
  exit: Exit.Exit<unknown, unknown>
) => Effect.Effect<void>
self
CloseableScope
required
The scope to close
exit
Exit.Exit<unknown, unknown>
required
The exit value to pass to finalizers
return
Effect.Effect<void>
An effect that closes the scope
import { Scope, Effect, Exit } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope.make()
  
  // Add finalizers...
  
  // Close the scope
  yield* Scope.close(scope, Exit.succeed(void 0))
})

fork

Forks a new child scope with the specified execution strategy.
const fork: (
  self: Scope,
  strategy: ExecutionStrategy.ExecutionStrategy
) => Effect.Effect<CloseableScope>
self
Scope
required
The parent scope
strategy
ExecutionStrategy.ExecutionStrategy
required
How to execute the child scope’s finalizers
return
Effect.Effect<CloseableScope>
An effect producing a child scope
The child scope will automatically close when the parent scope closes.

extend

Extends the scope of an effect without closing when it completes.
const extend: {
  (scope: Scope): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope>>
  <A, E, R>(effect: Effect.Effect<A, E, R>, scope: Scope): Effect.Effect<A, E, Exclude<R, Scope>>
}
effect
Effect.Effect<A, E, R>
required
An effect that requires a Scope
scope
Scope
required
The scope to provide
return
Effect.Effect<A, E, Exclude<R, Scope>>
The effect with scope provided
import { Scope, Effect } from "effect"

const acquireResource = Effect.gen(function* () {
  const scope = yield* Scope
  yield* Scope.addFinalizer(scope, Effect.log("Resource released"))
  return "resource"
})

const program = Effect.gen(function* () {
  const outerScope = yield* Scope.make()
  
  // Extend the resource into the outer scope
  const resource = yield* Scope.extend(outerScope)(acquireResource)
  
  // Resource won't be released until outerScope closes
  yield* Effect.log(`Using ${resource}`)
})

use

Provides a closeable scope to an effect and closes it when the effect completes.
const use: {
  (scope: CloseableScope): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope>>
  <A, E, R>(effect: Effect.Effect<A, E, R>, scope: CloseableScope): Effect.Effect<A, E, Exclude<R, Scope>>
}
effect
Effect.Effect<A, E, R>
required
An effect that requires a Scope
scope
CloseableScope
required
The scope to provide and close
return
Effect.Effect<A, E, Exclude<R, Scope>>
The effect with scope managed automatically
import { Scope, Effect } from "effect"

const acquireResource = Effect.gen(function* () {
  const scope = yield* Scope
  yield* Scope.addFinalizer(scope, Effect.log("Cleanup"))
  return "resource"
})

const program = Effect.gen(function* () {
  const scope = yield* Scope.make()
  
  // Scope will close when acquireResource completes
  const resource = yield* Scope.use(scope)(acquireResource)
  
  return resource
})

Common Patterns

Resource Management

Scopes are commonly used with Effect.acquireRelease for safe resource management:
import { Effect, Scope } from "effect"

const resource = Effect.acquireRelease(
  Effect.sync(() => {
    console.log("Acquiring resource")
    return { id: 1 }
  }),
  (res) => Effect.sync(() => {
    console.log(`Releasing resource ${res.id}`)
  })
)

const program = Effect.scoped(
  Effect.gen(function* () {
    const res = yield* resource
    yield* Effect.log(`Using resource ${res.id}`)
  })
)
// Acquiring resource
// Using resource 1  
// Releasing resource 1

Manual Scope Control

For more control over scope lifetime:
import { Effect, Scope, Exit } from "effect"

const program = Effect.gen(function* () {
  const scope = yield* Scope.make()
  
  yield* Scope.addFinalizer(
    scope,
    Effect.log("First finalizer")
  )
  
  yield* Scope.addFinalizer(
    scope,
    Effect.log("Second finalizer")
  )
  
  // Do work...
  
  // Manually close when ready
  yield* Scope.close(scope, Exit.succeed(void 0))
})
// Output:
// Second finalizer
// First finalizer
Finalizers run in reverse order of registration (LIFO - Last In, First Out).

Build docs developers (and LLMs) love