Lambda Prelude is built for long-running backend services. The basic approach is to produce a single native binary and run it under a Linux init system, container, or orchestrator.

Build

lambda-prelude build src/main.lp --out my-service

The output is a real native binary linked by ocamlopt. No interpreter is required at runtime. Sends whose receiver class the type checker can pin down are lowered to direct OCaml calls; the rest go through the runtime dispatcher the binary links.

Cross-Platform Targets

Both are exercised before a feature is considered complete. A change that works only on one platform is treated as incomplete.

Plugin Loading

PostgreSQL / MariaDB / MySQL / Redis / Valkey bindings load through OCaml's Dynlink, under both the interpreter and the AOT binary. The plugin file (.cmxs) is searched in this order (first hit wins):

  1. $LAMBDA_PRELUDE_PLUGINS if set — single override directory
  2. ./plugins/ under the working directory
  3. <exe_dir>/plugins/ next to the running binary (installed layout)
  4. <exe_dir>/../plugins/ (Linux package layout)
  5. _build/default/plugins/ (dev workflow)

The AOT binary has the same runtime compiled in, so it loads these plugins identically — there is no plugin capability lost by building. TORM ships in the standard library and works with every backend; only the matching plugin needs to be on the search path at runtime.

Service Layout

A small service typically looks like:

my-service/
  main.lp
  config.lp
  service/
    XA001Save.lp
    XA001GetAll.lp
  tests/
    save_test.lp
    getall_test.lp

lambda-prelude new my-service scaffolds the entry point and tests directory.

lambda-prelude new my-service
cd my-service
lambda-prelude run main.lp
lambda-prelude test tests
lambda-prelude build main.lp --out my-service

Init Integration

The binary is a regular long-running process. Wire it into the host system the same way any other daemon would be:

No companion VM, no runtime image to upload, no JIT warmup window.

Crash Recovery

Within the binary, supervision trees handle actor-level failures. Across binaries, the host system's restart policy handles process-level failures.

Treat the supervisor tree as the inner layer (millisecond-scale, in-process restart) and the OS init system as the outer layer (second-scale, process-level restart). This is the same separation Erlang uses between supervisor and heart.