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
- Windows — MinGW-w64 linked binary. No Cygwin DLL at runtime. First-class development target.
- Linux — standard ELF binary. First-class production target.
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):
$LAMBDA_PRELUDE_PLUGINSif set — single override directory./plugins/under the working directory<exe_dir>/plugins/next to the running binary (installed layout)<exe_dir>/../plugins/(Linux package layout)_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-serviceInit Integration
The binary is a regular long-running process. Wire it into the host system the same way any other daemon would be:
- systemd — a single
ExecStart=unit,Restart=on-failure,User=for an unprivileged service account - Docker —
FROM debian:stable-slimis enough; copy the binary in and run it - Kubernetes — standard
Deployment+Service; readiness probe hits/healthzif the service exposes one
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.