Skip to main content
On this pageOverview

Resources

Overview

Commands are self-contained by default — each execution starts fresh with no shared state. But some browser APIs like AudioContext, RTCPeerConnection, or CanvasRenderingContext2D need a single long-lived instance shared across commands. That’s what resources is for.

Define a service using Effect.Service, then pass its default layer to makeElement or makeApplication via the resources config field. The runtime memoizes the layer once and provides it to every command and subscription automatically.

import { Effect } from 'effect'
import { Runtime } from 'foldkit'
import { Command } from 'foldkit/command'

// 1. Define a service using Effect.Service
class AudioContextService extends Effect.Service<AudioContextService>()(
  'AudioContextService',
  { sync: () => new AudioContext() },
) {}

// 2. Commands yield the service — provided via the resources layer
const playNote = (
  frequency: number,
  duration: number,
): Command<typeof PlayedNote, never, AudioContextService> =>
  Effect.gen(function* () {
    const audioContext = yield* AudioContextService
    const oscillator = audioContext.createOscillator()
    oscillator.frequency.setValueAtTime(
      frequency,
      audioContext.currentTime,
    )
    oscillator.connect(audioContext.destination)
    oscillator.start()
    oscillator.stop(audioContext.currentTime + duration)
    return PlayedNote()
  })

// 3. Pass the service's default layer to makeElement
const element = Runtime.makeElement({
  Model,
  init,
  update,
  view,
  container: document.getElementById('root')!,
  resources: AudioContextService.Default,
})

Commands declare their resource requirements in the type signature via the third type parameter of Command. This makes dependencies explicit and type-checked — if a command requires a service that isn’t provided via resources, you’ll get a compile error.

When not to use resources

Resources are for mutable browser singletons with lifecycle — things that must be created once and reused. Stateless services like HttpClient or BrowserKeyValueStore should be provided per-command with Effect.provide instead.

Providing Multiple Services

The resources field takes a single Layer, but Effect layers compose. Use Layer.mergeAll to combine multiple service layers into one.

import { Layer } from 'effect'
import { Runtime } from 'foldkit'

const element = Runtime.makeElement({
  Model,
  init,
  update,
  view,
  container: document.getElementById('root')!,
  resources: Layer.mergeAll(
    AudioContextService.Default,
    WebRTCService.Default,
    CanvasService.Default,
  ),
})