Skip to content
Docs menu / Micro for Effect Users

Micro for Effect Users

The Micro module is designed as a lighter alternative to the standard Effect module, tailored for situations where it is beneficial to reduce the bundle size.

This module is standalone and does not include more complex functionalities such as Layer, Ref, Queue, and Deferred. This feature set makes Micro especially suitable for libraries that wish to utilize Effect functionalities while keeping the bundle size to a minimum, particularly for those aiming to provide Promise-based APIs.

Micro also supports use cases where a client application uses Micro, and a server employs the full suite of Effect features, maintaining both compatibility and logical consistency across various application components.

Integrating Micro adds a minimal footprint to your bundle, starting at 5kb gzipped, which may increase depending on the features you use.

Importing Micro

Micro is a part of the Effect library and can be imported just like any other module:

import { Micro } from "effect"

You can also import it using a namespace import like this:

import * as Micro from "effect/Micro"

Both forms of import allow you to access the functionalities provided by the Micro module.

However an important consideration is tree shaking, which refers to a process that eliminates unused code during the bundling of your application. Named imports may generate tree shaking issues when a bundler doesn’t support deep scope analysis.

Here are some bundlers that support deep scope analysis and thus don’t have issues with named imports:

  • Rollup
  • Webpack 5+

Main Types

Micro

The Micro type uses three type parameters:

┌─── Represents the success type
│ ┌─── Represents the error type
│ │ ┌─── Represents required dependencies
▼ ▼ ▼
Micro<Success, Error, Requirements>

which mirror those of the Effect type.

MicroExit

The MicroExit type is a streamlined version of the Exit type, designed to capture the outcome of a Micro computation. It can either be successful, containing a value of type A, or it can fail, containing an error of type E wrapped in a MicroCause.

type MicroExit<A, E> = MicroExit.Success<A, E> | MicroExit.Failure<A, E>

MicroCause

The MicroCause type is a streamlined version of the Cause type.

Similar to how Cause is a union of types, MicroCause comes in three forms:

type MicroCause<E> = Die | Fail<E> | Interrupt
Variant Description
Die Indicates an unforeseen defect that wasn’t planned for in the system’s logic.
Fail<E> Covers anticipated errors that are recognized and typically handled within the application.
Interrupt Signifies an operation that has been purposefully stopped.

MicroSchedule

The MicroSchedule type is a streamlined version of the Schedule type.

type MicroSchedule = (attempt: number, elapsed: number) => Option<number>

Represents a function that can be used to calculate the delay between repeats.

The function takes the current attempt number and the elapsed time since the first attempt, and returns the delay for the next attempt. If the function returns None, the repetition will stop.

How to Use This Guide

Below, you’ll find a series of comparisons between the functionalities of Effect and Micro. Each table lists a functionality of Effect alongside its counterpart in Micro. The icons used have the following meanings:

  • ⚠️: The feature is available in Micro, but with some differences from Effect.
  • ❌: The feature is not available in Effect.

Creating Effects

Effect Micro ⚠️
Effect.try Micro.try requires a try block
Effect.tryPromise Micro.tryPromise requires a try block
Effect.sleep Micro.sleep only handles milliseconds
Effect.failCause Micro.failWith uses MicroCause instead of Cause
Effect.failCauseSync Micro.failWithSync uses MicroCause instead of Cause
Micro.make
Micro.fromOption
Micro.fromEither

Running Effects

Effect Micro ⚠️
Effect.runSyncExit Micro.runSyncExit returns a MicroExit instead of an Exit
Effect.runPromiseExit Micro.runPromiseExit returns a MicroExit instead of an Exit
Effect.runFork Micro.runFork returns a MicroFiber instead of a RuntimeFiber

runSyncExit

The Micro.runSyncExit function is used to execute an Effect synchronously, which means it runs immediately and returns the result as a MicroExit.

Example (Handling Results as MicroExit)

import { Micro } from "effect"
const result1 = Micro.runSyncExit(Micro.succeed(1))
console.log(result1)
/*
Output:
{
"_id": "MicroExit",
"_tag": "Success",
"value": 1
}
*/
const result2 = Micro.runSyncExit(Micro.fail("my error"))
console.log(result2)
/*
Output:
{
"_id": "MicroExit",
"_tag": "Failure",
"cause": {
"_tag": "Fail",
"traces": [],
"name": "MicroCause.Fail",
"error": "my error"
}
}
*/

runPromiseExit

The Micro.runPromiseExit function is used to execute an Effect and obtain the result as a Promise that resolves to a MicroExit.

Example (Handling Results as MicroExit)

import { Micro } from "effect"
Micro.runPromiseExit(Micro.succeed(1)).then(console.log)
/*
Output:
{
"_id": "MicroExit",
"_tag": "Success",
"value": 1
}
*/
Micro.runPromiseExit(Micro.fail("my error")).then(console.log)
/*
Output:
{
"_id": "MicroExit",
"_tag": "Failure",
"cause": {
"_tag": "Fail",
"traces": [],
"name": "MicroCause.Fail",
"error": "my error"
}
}
*/

runFork

The Micro.runFork function executes the effect and return a MicroFiber that can be awaited, joined, or aborted.

You can listen for the result by adding an observer using the addObserver method.

Example (Observing an Asynchronous Effect)

import { Micro } from "effect"
// ┌─── MicroFiber<number, never>
// ▼
const fiber = Micro.succeed(42).pipe(Micro.delay(1000), Micro.runFork)
// Attach an observer to log the result when the effect completes
fiber.addObserver((result) => {
console.log(result)
})
console.log("observing...")
/*
Output:
observing...
{
"_id": "MicroExit",
"_tag": "Success",
"value": 42
}
*/

Building Pipelines

Effect Micro ⚠️
Effect.andThen Micro.andThen doesn’t handle Promise or () => Promise as argument
Effect.tap Micro.tap doesn’t handle () => Promise as argument
Effect.all Micro.all no batching and mode options
Effect.forEach Micro.forEach no batching option
Effect.filter Micro.filter no batching option
Effect.filterMap Micro.filterMap the filter is effectful

Expected Errors

Effect Micro ⚠️
Effect.exit Micro.exit returns a MicroExit instead of an Exit

Unexpected Errors

Effect Micro
Micro.catchCauseIf

Timing Out

Effect Micro
Micro.timeoutOrElse

Requirements Management

To access a service while using Micro.gen, you need to wrap the service tag using the Micro.service function:

Example (Accessing a Service in Micro.gen)

import { Micro, Context } from "effect"
class Random extends Context.Tag("MyRandomService")<
Random,
{ readonly next: Micro.Micro<number> }
>() {}
const program = Micro.gen(function* () {
// const random = yield* Random // this doesn't work
const random = yield* Micro.service(Random)
const randomNumber = yield* random.next
console.log(`random number: ${randomNumber}`)
})
const runnable = Micro.provideService(program, Random, {
next: Micro.sync(() => Math.random()),
})
Micro.runPromise(runnable)
/*
Example Output:
random number: 0.8241872233134417
*/

Scope

Effect Micro ⚠️
Scope MicroScope returns a MicroScope instead of a Scope
Scope.make Micro.scopeMake returns a MicroScope instead of a Scope

Retrying

Effect Micro ⚠️
Effect.retry Micro.retry different options

Repetition

Effect Micro ⚠️
Effect.repeat Micro.repeat different options
Micro.repeatExit

Timing out

Effect Micro
Micro.timeoutOrElse

Sandboxing

Effect Micro ⚠️
Effect.sandbox Micro.sandbox returns a MicroCause<E> instead of Cause<E>

Error Channel Operations

Effect Micro ⚠️
Micro.filterOrFailWith
Effect.tapErrorCause Micro.tapErrorCause MicroCause<E> instead of Cause<E>
Micro.tapCauseIf
Effect.tapDefect Micro.tapDefect unknown instead of Cause<never>

Requirements Management

Effect Micro ⚠️
Effect.provide Micro.provideContext only handles Context
Micro.provideScope
Micro.service

Scoping, Resources and Finalization

Effect Micro ⚠️
Effect.addFinalizer Micro.addFinalizer MicroExit instead of Exit and no R
Effect.acquireRelease Micro.acquireRelease MicroExit instead of Exit
Effect.acquireUseRelease Micro.acquireUseRelease MicroExit instead of Exit
Effect.onExit Micro.onExit MicroExit instead of Exit
Effect.onError Micro.onError uses MicroCause instead of Cause
Micro.onExitIf

Concurrency

Effect Micro ⚠️
Effect.fork Micro.fork MicroFiber instead of RuntimeFiber
Effect.forkDaemon Micro.forkDaemon MicroFiber instead of RuntimeFiber
Effect.forkIn Micro.forkIn MicroFiber instead of RuntimeFiber
Effect.forkScoped Micro.forkScoped MicroFiber instead of RuntimeFiber