---
title: "How to enable the Effect extension"
description: "Use the supported Effect 4 preview, understand its version contract, and configure your project."
image: "https://hem.run/social/hem.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://hem.run/llms.txt
> Use this file to discover all available pages before exploring further.

# How to enable the Effect extension

The Effect extension is disabled until you configure a transport module. When disabled, Hem does not emit Effect imports, and extension syntax and diagnostics are unavailable. Inside Effect code, `raise`, `catch`, and `use` use Effect's failure and resource semantics. Ordinary synchronous code keeps its core semantics.

## Supported preview

Hem's Effect extension targets the native `effect` package's Effect 4 API:

| Part | Supported configuration |
| --- | --- |
| Runtime | Exactly `effect@4.0.0` |
| Compiler transport | The `effect` package itself; generated code imports nothing else |
| Project setting | `"effectImportSource": "effect"` |
| Package identity | One physical Effect installation shared by the whole application |

Effect 3 and other Effect 4 versions are outside this support contract. A
passing capability probe does not extend it.

### Upgrading from the release candidate

The supported runtime is now the stable `4.0.0` release, replacing
`4.0.0-rc.117`. Update the exact `effect` dependency and lockfile together. If
you use `@effect/vitest`, update it to `4.0.0` as well; it requires Vitest 5.
Keep `hem.effectImportSource` set to `"effect"`. Hem's generated code already
uses the native Effect 4 API, so this upgrade does not change Hem syntax.

Effect 4 moves imports such as `effect/unstable/http` to `effect/http`.
These APIs can still be unstable: consult their `@stability` tags before
upgrading. See the [Effect 4 migration guide](https://github.com/Effect-TS/effect/blob/main/MIGRATION.md)
for package and API changes in your handwritten TypeScript and ecosystem imports.
After updating, run `hem check`, `hem build`, and your application's tests.

### What the generated code looks like

Emitted TypeScript is the Effect 4 code you would write by hand: `service`
becomes a `Context.Service` class, `error` becomes `Data.TaggedError`, blocks
become `Effect.gen`, binding `catch` arms become `Effect.catch`, `await` inside a
block becomes `Effect.tryPromise` with `Cause.UnknownError` as its rejection
type, and Effect's eager carriers are `Option` and `Result`. There is no Hem
runtime, adapter, or helper module between the emitted code and the library.

## Install the runtime dependency

Hem's packages are not published yet. Inside the Hem repository, use the exact
runtime pin in the application's `package.json`:

```json
{
  "dependencies": {
"effect": "4.0.0"
  }
}
```

Install with the workspace's package manager. A packed preview consumer installs
the same pinned version.

Keep a lockfile and avoid installing a second copy of Effect. Equal version
numbers alone do not establish one package identity; HEM4116 reports duplicate
physical installations.

### Repair HEM4116

The diagnostic names each package root and a representative import or reexport
that reaches it, including the source file and line. When no incoming edge is
available, it names a participating declaration. These references show which
packages to inspect; they are not an exhaustive import graph.

For example, an application's native tests may resolve Effect from a pnpm
installation while a generated module still resolves a second copy left by Bun.
Restore the installation with the project's chosen package manager and existing
lockfile. For this repository, the repair command is `pnpm install --frozen-lockfile`.
Recheck the reported roots before changing versions or running a dedupe command;
the supported preview requires the exact version above.

Keep native tests and consumers in the project. Run the full project's Hem check,
build and behavior tests after repair. A small fixture that imports only `effect`
can pass while the application's complete graph still contains two roots.
Removing those tests or suppressing the identity check would conceal the problem.

## Configure the transport

Set `effectImportSource` in your `tsconfig.json` so the CLI, language server, Vite plugin, and `hem test` share the same configuration:

```json
{
  "hem": { "effectImportSource": "effect" }
}
```

This names the module Hem checks and uses for generated imports.

To override the transport in Vite for a single build, pass the plugin option:

```ts
hem({ effectImportSource: "effect" });
```

Use `tsconfig.json` as the primary configuration. If the Vite plugin setting differs from `tsconfig.json`, your editor and build system will use different settings.

## Use library APIs explicitly

Import the namespaces you call directly from `effect`, as the examples do; Hem
adds the imports its own generated code needs (`Effect`, `Context`, `Data`,
`Cause`, `Option`, `Result`) and aliases them when your names collide. Other
Effect modules and ecosystem packages remain ordinary imports. They must share
the same Effect installation and satisfy the checked types.

Arbitrary ecosystem packages are not certified by this preview; check their
version requirements and runtime behavior separately. When consulting Effect
documentation, check it against the pinned version rather than assuming current
examples or Effect 3 examples apply unchanged.

## Check that the probe passes

Before compiling, Hem checks the configured module for the Effect 4 APIs its
generated code uses in `Effect`, `Layer`, `Data`, `Context`, `Cause`, `Option`,
and `Result`, and that `Effect.fromOption` and `Effect.fromResult` lift the
module's own carriers inside `Effect.gen`.

```sh
hem check
```

If an API is missing, the compiler reports error HEM3001 and halts the build. This indicates that the installed module does not support the required features.

Types are validated by declaration origin rather than name, so local types named `Effect` will not conflict with the library.

Hem's compatibility tests exercise resource release, interruption, typed errors,
carrier lifts, and Layer wiring. These tests support the named configuration;
they are not a guarantee for every Effect API or application. Run your own
application tests as well.

Imports from the `effect` barrel, public subpaths such as `effect/Effect` and
`effect/Result`, and typed reexports share the same carrier checks. Hem follows
the configured package's type declarations, including type aliases; constructor
names on unrelated local types do not acquire Effect behavior.

## Testing an alternate transport

```sh
hem test --effect ./vendor/effect-next
```

This command runs your test suite against an alternate package without updating
your configuration. It is a compatibility experiment, not a supported upgrade
path. Passing the capability probe establishes that required API shapes exist;
it does not certify runtime compatibility. Keep the pinned version for the
supported preview.

## What turns on

Enabling the extension adds these features to `.hem` files:

- `effect { }` blocks and the postfix `!` operator for binding effects
- `effect traced` functions with span names generated from the module and binding
- `service` declarations, emitted as `Context.Service` classes
- `resource { }` blocks and `defer` statements for scoped cleanup
- `and` groups that run concurrently and cancel remaining tasks on the first error
- `await` within effect blocks, converting Promises using Effect's promise constructor
- `error` declarations emitted as tagged errors rather than standard classes
- Explicit lifts from standard `Option` and `Result` types, and from Effect's own `Option` and `Result`, into the Effect error channel

The `error` declaration works across both modes: core and Effect builds both extend `Error` and include a `_tag` property, allowing modules with and without the extension to share errors.

The compiler also enables the HEM41xx diagnostic checks, which flag unsafe patterns such as calling Effect runners inside an effect or returning unhandled Promises in a success channel. See the [Effect boundaries reference](/reference/effect-boundaries) for the complete list.

## Turning it back off

Remove `effectImportSource` from your configuration. Any code using Effect-specific syntax will fail to compile. There is no partial-enablement mode.

## Next

[Part II of the tour](/tour/effect-a-description-not-an-action) covers each Effect construct and its generated TypeScript.

For a complete small example, compare the
[report application in Hem and native TypeScript + Effect](https://github.com/ozanvos/hem/tree/main/examples/effect-report).
It combines input validation, two services, concurrent reads, selective recovery,
and scoped cleanup. Both versions import the same `effect` package and run the
same tests. Its data and resource lease are synthetic; the example uses the
preview configuration described above.

Source: https://hem.run/guides/enable-effect/index.mdx
