# Acquire / release

The `acquireRelease` family is the recommended way to manage a resource. It
pairs an **acquire** effect with a **release** effect and guarantees the release
runs when the scope closes. Crucially, acquisition runs in an *uninterruptible*
region: once you have started acquiring, you are guaranteed to either fully
acquire the resource (and register its release) or not acquire it at all. There
is no window where a resource is half-open with no finalizer attached — the
classic source of leaks.

## `Effect.acquireRelease` — scoped resources

`Effect.acquireRelease(acquire, release)` produces an `Effect` that yields the
resource and adds `release` to the current scope. The release receives the
`Exit` the scope closed with, so it can behave differently on success vs.
failure.

```ts
import { Effect, Exit, Console } from "effect"

interface FileHandle {
  readonly path: string
}

// `acquire` opens the resource; `release` closes it and can inspect the Exit.
const openFile = (path: string) =>
  Effect.acquireRelease(
    Console.log(`opening ${path}`).pipe(Effect.as<FileHandle>({ path })),
    (handle, exit) =>
      Console.log(
        `closing ${handle.path} (${Exit.isSuccess(exit) ? "ok" : "errored"})`
      )
  )

const program = Effect.gen(function*() {
  // Yielding the resource registers its release in the surrounding scope.
  const file = yield* openFile("/tmp/data.txt")
  yield* Console.log(`reading ${file.path}`)
  return "contents"
})

// `Effect.scoped` defines the lifetime: the file is closed when the block ends.
Effect.runPromise(Effect.scoped(program)).then(console.log)
/*
Output:
opening /tmp/data.txt
reading /tmp/data.txt
closing /tmp/data.txt (ok)
contents
*/
```

The resource type carries `Scope` in its requirements
(`Effect<FileHandle, never, Scope>`) until you wrap it with `Effect.scoped` (or
provide it to a Layer, see below). That requirement is the type system enforcing
that the resource must live inside *some* scope.
**Disposable interop:** If your resource already implements JavaScript's `Disposable` or
  `AsyncDisposable` protocol (a `[Symbol.dispose]` / `[Symbol.asyncDispose]`
  method), use `Effect.acquireDisposable` to acquire it — Effect will call the
  disposal method as the finalizer for you.

## `Effect.acquireUseRelease` — the bracket pattern

When a resource is acquired, used, and released all in one place, reach for
`Effect.acquireUseRelease(acquire, use, release)`. It is the classic *bracket*:
the resource is acquired, the `use` function runs with it, and `release` runs
afterward — even if `use` fails or is interrupted. Unlike `acquireRelease`, it
does **not** require a `Scope`; the lifetime is exactly the `use` call.

```ts
import { Effect, Console } from "effect"

interface Connection {
  readonly id: number
  readonly query: (sql: string) => Effect.Effect<ReadonlyArray<string>>
}

let nextId = 0

const acquire = Effect.sync<Connection>(() => {
  const id = ++nextId
  return {
    id,
    query: (sql) => Console.log(`[conn ${id}] ${sql}`).pipe(Effect.as(["row"]))
  }
}).pipe(Effect.tap((c) => Console.log(`acquired connection ${c.id}`)))

const program = Effect.acquireUseRelease(
  // 1. acquire the resource
  acquire,
  // 2. use it — this is the only place the resource is in scope
  (conn) => conn.query("SELECT 1"),
  // 3. release it, with access to the resource and the Exit of `use`
  (conn) => Console.log(`releasing connection ${conn.id}`)
)

Effect.runPromise(program).then(console.log)
/*
Output:
acquired connection 1
[conn 1] SELECT 1
releasing connection 1
[ 'row' ]
*/
```

**Which one do I use?**

- Use **`acquireUseRelease`** when acquire → use → release is a single
  self-contained operation. It needs no scope and reads top to bottom.
- Use **`acquireRelease`** when the resource must outlive a single expression —
  when several steps share it, or when it backs a long-lived service. You decide
  its lifetime by choosing where to call `Effect.scoped`, or by attaching it to
  a Layer.

## Tying a resource to a service Layer

The most common production pattern is to acquire a resource while constructing a
service. A [Layer](https://effect.plants.sh/services-and-layers/) built with `Layer.effect` runs inside
its own scope, so a resource acquired with `acquireRelease` during construction
is released exactly when the layer is torn down — typically at application
shutdown. You get correct startup/shutdown ordering for free.

```ts
import { Config, Context, Effect, Layer, Redacted, Schema } from "effect"
import * as NodeMailer from "nodemailer"

// Use `Schema.Defect` to carry an unknown thrown cause on the error.
class SmtpError extends Schema.TaggedErrorClass<SmtpError>()("SmtpError", {
  cause: Schema.Defect
}) {}

// A v4 service: `Context.Service` with a static `layer`.
class Smtp extends Context.Service<Smtp, {
  send(message: {
    readonly to: string
    readonly subject: string
    readonly body: string
  }): Effect.Effect<void, SmtpError>
}>()("app/Smtp") {
  static readonly layer = Layer.effect(
    Smtp,
    Effect.gen(function*() {
      const user = yield* Config.string("SMTP_USER")
      const pass = yield* Config.redacted("SMTP_PASS")

      // The transporter is acquired while the layer is built and closed when
      // the layer's scope closes — i.e. when the app shuts down. No manual
      // wiring of `Scope` is needed; `Layer.effect` provides it.
      const transporter = yield* Effect.acquireRelease(
        Effect.sync(() =>
          NodeMailer.createTransport({
            host: "smtp.example.com",
            port: 587,
            secure: false,
            auth: { user, pass: Redacted.value(pass) }
          })
        ),
        (transporter) => Effect.sync(() => transporter.close())
      )

      const send = Effect.fn("Smtp.send")((message: {
        readonly to: string
        readonly subject: string
        readonly body: string
      }) =>
        Effect.tryPromise({
          try: () =>
            transporter.sendMail({
              from: "Acme Cloud <cloud@acme.com>",
              to: message.to,
              subject: message.subject,
              text: message.body
            }),
          catch: (cause) => new SmtpError({ cause })
        }).pipe(Effect.asVoid)
      )

      return Smtp.of({ send })
    })
  )
}
```

Because the cleanup is baked into the layer, every consumer of `Smtp` benefits
automatically — they never see the transporter, the scope, or the finalizer.
This is the idiomatic place for `acquireRelease`: at the seam between the outside
world and your service graph.
**Dynamic, keyed resources:** When you need one resource *per key* — say a connection pool per tenant —
  build the layer with `LayerMap.Service`, which lazily builds (and idles out) a
  layer for each key. See [Services &amp; Layers](https://effect.plants.sh/services-and-layers/).

For resources that run continuously in the background rather than answering
calls, see [background tasks](https://effect.plants.sh/resource-management/background-tasks/).