Bootloader
The wippy/bootloader module orchestrates application initialization by discovering and running bootloader functions in a defined order at startup. Other framework modules (migrations, encryption, index refresh) register bootloaders to run their own initialization steps.
Setup
Add the module to your project:
wippy add wippy/bootloader
wippy install
Declare the dependency and the required application host:
version: "1.0"
namespace: app
entries:
- name: processes
kind: process.host
lifecycle:
auto_start: true
- name: os_env
kind: env.storage.os
- name: dep.bootloader
kind: ns.dependency
component: wippy/bootloader
version: "*"
parameters:
- name: application_host
value: app:processes
- name: env_storage
value: app:os_env
The bootloader itself runs as wippy.bootloader:bootloader.service (a process.service with auto_start: true). Nothing else is required to activate it.
How It Works
At startup the bootloader:
- Discovers every entry with
meta.type: bootloaderfrom the registry. - Sorts them by
meta.orderascending (lowest first). - Executes each one sequentially as a Lua function.
- Stops on the first error that returns
status = "error". - Reports total / success / failed / skipped counts when finished.
Bootloaders are autonomous — each one checks its own conditions, does its work, and reports a structured result.
Defining a Bootloader
A bootloader is any function.lua entry with meta.type: bootloader:
- name: seed_defaults
kind: function.lua
meta:
type: bootloader
order: 50
description: Seed default rows for a new install
source: file://seed_defaults.lua
method: run
modules:
- logger
imports:
sql: :sql
| Field | Required | Description |
|---|---|---|
meta.type |
Yes | Must be bootloader |
meta.order |
No | Execution order (default 100); lower runs first |
meta.description |
No | Human-readable summary |
meta.requires |
No | Dependency hints surfaced in logs |
Return Contract
The method returns a table describing the outcome:
local function run()
local ok, err = apply_seed()
if err then
return {
status = "error",
message = "seed failed: " .. tostring(err)
}
end
if not ok then
return {
status = "skipped",
message = "already seeded"
}
end
return {
status = "success",
message = "seeded default rows"
}
end
return { run = run }
| Status | Meaning |
|---|---|
success |
Work completed |
skipped |
No-op (already done, precondition unmet) |
error |
Failure — stops the boot sequence |
A bootloader that raises a Lua error is treated as error.
Execution Order
Lower order values run first. Reserve low orders for infrastructure:
| Order | Typical Use |
|---|---|
10 |
Secrets and encryption keys (provided by the module) |
20 |
Schema migrations (provided by wippy/migration) |
50 |
Data seeding, search index warmup |
100 |
Default — application-level tasks |
When two bootloaders share an order, execution order between them is not guaranteed.
Built-in Bootloaders
Encryption Key (order 10)
Generates a 256-bit ENCRYPTION_KEY and stores it through the configured env_storage if no value is present. Other modules (security, usage tracking) read this variable for envelope encryption. Skipped when the variable already exists.
Migration Bootloader (order 20)
Provided by wippy/migration. Discovers every entry with meta.type: migration, groups them by meta.target_db, and applies the pending ones. See Migrations.
Observing Boot Status
The service logs one line per bootloader (SUCCESS, FAILED, SKIPPED) with the entry ID, order, and duration. The final summary line reports aggregate counts. A failed bootloader aborts startup — the supervisor's restart policy then applies to bootloader.service.
See Also
- Migrations - Migration bootloader and DSL
- Supervision - Service lifecycle and restart policy
- Framework Overview - Framework module usage