# Runtime

An `Effect` is just a description of a computation — building one runs nothing.
Nothing happens until you hand that description to a **runtime**, which spawns a
fiber to actually carry it out. This is the same principle as a lazy `() =>
Promise`: you compose effects freely, then execute the whole program in one
place.

The golden rule is to **run effects at the edge** of your application. Keep the
vast majority of your logic as composed effects, and call a `run*` function (or
a platform `runMain`) once, as close to the "outside world" as possible — your
`main.ts`, an HTTP handler, a test. Pushing execution to the edge keeps your
code composable, testable, and free of half-run side effects scattered through
the middle of your program.

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

// A description. Nothing has happened yet.
const program = Effect.gen(function*() {
  yield* Effect.log("Hello from a fiber")
  return 42
})

// Execution happens here, once, at the edge.
Effect.runPromise(program).then((n) => console.log(n))
// Output:
// ... level=INFO message="Hello from a fiber"
// 42
```

## What's in this section

- **[Running effects](https://effect.plants.sh/runtime/running-effects/)** — the `run*` family
  (`runSync`, `runPromise`, `runFork`, and their `Exit` variants), and how to
  choose between them.
- **[Running as an entrypoint](https://effect.plants.sh/runtime/run-main/)** — `NodeRuntime.runMain` /
  `BunRuntime.runMain`, the production-grade way to make an Effect your process
  root, with signal handling and graceful shutdown.
- **[Launching applications](https://effect.plants.sh/runtime/layer-launch/)** — `Layer.launch`, for
  long-running apps (servers, workers) expressed entirely as layers.
- **[Managed runtime](https://effect.plants.sh/services-and-layers/managed-runtime/)** — build a single
  runtime from your application `Layer` and run many effects against it, so
  services and resources are shared instead of constructed per run. The way to
  bridge Effect into a non-Effect host (a web framework, a UI event loop).

## Choosing how to run

| You want…                                  | Use                                          |
| ------------------------------------------ | -------------------------------------------- |
| A process entrypoint (CLI, server, worker) | `NodeRuntime.runMain` / `BunRuntime.runMain` |
| A long-running app built from layers       | `Layer.launch` + `runMain`                   |
| To share services/resources across runs    | `ManagedRuntime.make(layer)`                 |
| A `Promise` for interop                    | `Effect.runPromise`                          |
| A background fiber to observe or interrupt | `Effect.runFork`                             |
| An immediate, purely synchronous result    | `Effect.runSync`                             |

For most applications you will reach for `runMain` rather than calling the
low-level `run*` functions directly — it adds error reporting and graceful
shutdown on top of `runFork`. The `Effect.run*` functions are the right tool
when embedding Effect inside an existing host (a React event handler, an Express
route, an existing async function).

When that host fires events repeatedly and your effects need shared services
(database pools, config, caches), don't build a fresh layer on every event.
Build a [`ManagedRuntime`](https://effect.plants.sh/services-and-layers/managed-runtime/) once from your
application `Layer` and call `runtime.runPromise(effect)` per event — the layer
is constructed a single time and torn down with `runtime.dispose()` on shutdown.

Effects must have their requirements satisfied before they can run. A
`run*`/`runMain` function only accepts an `Effect<A, E, never>` — the `R`
channel must be empty. You eliminate requirements by providing
[services and layers](https://effect.plants.sh/services-and-layers/) before reaching the edge.

For writing your own process entrypoint or platform adapter, the core `Runtime`
module exposes the building blocks the `runMain` adapters are made from
(`makeRunMain`, `Teardown`, `defaultTeardown`, and the `errorExitCode` /
`errorReported` markers). Those are documented alongside the practical recipe on
the [Running as an entrypoint](https://effect.plants.sh/runtime/run-main/) page.

## Carrying services across many runs

For repeated execution against a shared set of services, a one-shot `run*` is
the wrong shape — it builds and discards everything each call. Build a
[`ManagedRuntime`](https://effect.plants.sh/services-and-layers/managed-runtime/) from your application
`Layer` once, then run effects against it as many times as you like. The layer
(and its scoped resources) is constructed lazily on first use and released when
you `dispose`.

```ts
import { Effect, Layer, ManagedRuntime } from "effect"

// Your application's services, expressed as a Layer.
const AppLayer = Layer.empty

const runtime = ManagedRuntime.make(AppLayer)

// Run many effects; services are shared, not rebuilt each time.
await runtime.runPromise(Effect.log("request 1"))
await runtime.runPromise(Effect.log("request 2"))

// Release layer resources on shutdown.
await runtime.dispose()
```

A `ManagedRuntime` exposes `runPromise`, `runPromiseExit`, `runFork`,
`runSync`, `runSyncExit`, plus `dispose` / `disposeEffect`. See
[Managed runtime](https://effect.plants.sh/services-and-layers/managed-runtime/) for the full reference
and framework-integration examples.