Skip to content

Lite, Core & Full

Compare the features, size, resource budget, and distribution of Lite, Core, and Full, then choose the right build.

Updated View as Markdown

Kiln comes in Lite, Core, and Full builds. All three use the same configuration model and native media modules. They differ in management features, whether FFmpeg is included, and their resource budgets.

The three variants

Dimension Lite Core Full
Default packager native native auto
Native HLS / DASH Yes Yes Yes
FFmpeg Not included Not included Bundled, 9.0
Login, M3U, playback Yes Yes Yes
SQLite database No Yes Yes
Admin console and admin API No Yes Yes
EPG No Yes Yes
OTLP and pprof No Yes Yes
Base image scratch Alpine Alpine plus FFmpeg
Purpose Fixed-config, low-resource playback node Complete, purely native deployment Complete deployment with compatibility

kiln:latest is an alias for the matching kiln:full, not a fourth runtime.

The default packager an image provides is injected through KILN_DEFAULT_PACKAGER_ENGINE and only applies when the config omits [packager].engine. The same config never changes behavior just because the image tag changed. See Media engine.

How they are built and shipped

Core and Full use exactly the same build entry point and compiler flags, and produce application binaries of identical size. The only differences are whether ffmpeg is present in the image and which environment variables are injected. Lite is the one variant that differs at compile time:

# The standard build shared by Core and Full
CGO_ENABLED=0 go build -trimpath -o kiln ./apps/server

# Lite swaps the entry point and the control plane through a build tag
CGO_ENABLED=0 go build -tags=lite -trimpath -o kiln ./apps/server

The lite tag selects a different main, so SQLite, the admin console, EPG, and telemetry export never enter the dependency closure. Lite is not a build with features switched off; those features are not compiled in at all.

The three images map to three Dockerfile targets:

docker build --target lite -f deploy/docker/Dockerfile -t kiln:lite .
docker build --target core -f deploy/docker/Dockerfile -t kiln:core .
docker build --target full -f deploy/docker/Dockerfile -t kiln:full .

Core builds for linux/amd64, linux/arm64, linux/arm/v7, and linux/arm/v6. For binary distribution, the install script’s --lite flag is Linux-only; every other platform installs the complete variant. See Install script.

Lite’s boundary

Lite exposes only /healthz, /readyz, /v1/auth/login, /v1/playlist.m3u, and /v1/play/*. It creates no SQLite database — data_dir holds nothing but auto-generated login keys and transient media files — which is what makes a read-only root filesystem practical.

Lite refuses to start, rather than silently ignoring the setting, when the config contains any of the following:

  • A packager engine other than native, globally or on any channel
  • An enabled EPG source
  • An OTLP export endpoint
  • pprof enabled

Lite’s fixed resource budget

Core and Full pick an internal profile from the container’s real memory. Lite pins the same budget regardless of how large the host is, so its low-memory profile stays identical everywhere it runs:

Effective value Lite For comparison: constrained Core / Full
Go soft memory limit 24 MiB 48 MiB
Native inflight ceiling 24 MiB 32 MiB
Max segment 20 MiB 20 MiB
Start / prefetch pipeline 1 / 1 1 / 1
GOGC 50 75
Reclaim media page cache Yes Yes

These values hold under both auto and constrained; only performance opts Lite out of adaptation entirely and uses the configured values instead. They are soft budgets for the Go heap and the media working set, not a guarantee about total container RSS.

Measured comparison

The numbers below come from a controlled in-repo benchmark run on 2026-07-23 against linux/arm64. All three variants ran on the same host, under the same container limits (1 CPU, 128 MiB), with the same config and the same media fixture, for 5 rounds each and 100 complete chains in total.

Build size (MB uses decimal bytes):

Variant Docker local image Kiln binary Additional FFmpeg
Lite 3.84 MB 9.31 MB none
Core 13.27 MB 22.22 MB none
Full 66.41 MB 22.22 MB 109.57 MB

Memory and chain stability:

Variant Post-load RSS median (range) Successful chains OOM
Lite 13.01 MiB (11.48 to 13.33) 100 / 100 0
Core 25.17 MiB (25.11 to 25.27) 100 / 100 0
Full 25.21 MiB (21.03 to 25.35) 100 / 100 0

What the run supports:

  • Lite’s image is 71.1% smaller than Core’s and 94.2% smaller than Full’s; its binary is 58.1% smaller than either.
  • Lite’s post-load RSS median is 48.3% below Core and 48.4% below Full. That drop comes from the runtime structure and the budget changing together, not from a smaller binary alone.
  • Core and a Full that never launched an ffmpeg child process show no explainable memory difference on the native path — roughly 0.14% apart. Bundling ffmpeg mainly costs distribution and disk.
  • In the official acceptance run, Lite completed 10 chains in a 1 CPU, 64 MiB container with a post-load RSS of 12.80 MiB and no OOM.

Environment and method

The host was an Apple M1 Max with 10 cores and 64 GiB, running containers on OrbStack under linux/arm64. Each Kiln container was limited to 1 CPU and 128 MiB with swap equal to memory, a read-only root filesystem, all Linux capabilities dropped, and no-new-privileges enabled. The three variants ran in interleaved order so a fixed sequence could not bias the caches.

The workload used the deterministic media fixtures in the repository rather than an external origin: a 320×180, 25 fps, 4 second H.264 test pattern at roughly 120 kbit/s paired with a 32 kbit/s stereo AAC tone. Every iteration fetched the master, media, init and segment of the encrypted DASH to HLS chain, plus the playlist, init and segment of the HLS proxy chain. Full defaults to auto, but the native engine handles this fixture end to end; the logs confirmed the native path and no ffmpeg child process appeared in the process table, so these numbers isolate the cost of the variant itself.

Memory is the VmRSS of PID 1 sampled after the 20th iteration of each round. The cgroup memory.peak accounts for file page cache alongside anonymous memory and swings much more between rounds, so it is used only to confirm the container boundary and OOM safety, never to rank the variants. Each metric reports the median and range across 5 rounds; the sample is small, so the comparison is descriptive only.

Reproducing it

Build and verify the images from the target revision first. The check covers variant labels, the default packager, the non-root user, the ffmpeg boundary, and Lite’s dependency closure and size ceiling:

make docker-images docker-verify-images

A single comparison round runs through deploy/docker/native-media-runtime-smoke.sh, with environment variables pinning the container limits, the iteration count and the expected resource profile:

KILN_SMOKE_CHECK_RESOURCES=1 \
KILN_SMOKE_CPUS=1 \
KILN_SMOKE_MEMORY=128m \
KILN_SMOKE_ITERATIONS=20 \
KILN_SMOKE_VARIANT=lite \
KILN_SMOKE_EXPECTED_PROFILE=lite \
  sh deploy/docker/native-media-runtime-smoke.sh kiln:lite-local

For Core and Full, swap KILN_SMOKE_VARIANT and KILN_SMOKE_EXPECTED_PROFILE for core / full and compact. A serious re-run should repeat at least 5 rounds and rotate the order, and comparisons across commits should hold the Docker version, host load, container limits, fixture and iteration count constant. Acceptance against real channels is a separate script, scripts/live-performance.sh, which measures cold start, first manifest, throughput ratio, RSS and CPU.

Picking one

Pick Lite

The node only needs login, M3U, and playback, every channel is handled natively, configuration lives in a file with no runtime database or console, and resource budget, image pull speed, or attack surface is the priority.

Pick Core

You want the full admin console, database, EPG, and observability, and you have already confirmed every DASH channel can be handled natively. It is far smaller than Full, but do not expect meaningfully lower process memory on the same native path.

Pick Full

Input compatibility comes first and you want the ffmpeg fallback available. On natively supported input its memory profile matches Core; when a fallback actually happens, size the container as “Kiln process plus ffmpeg child plus page cache”.

When in doubt, start with Full, get the channels playing, confirm the logs show the native path everywhere, and then move to Core. Deploy Lite separately when you need edge playback nodes. All three share the same configuration model, so migrating is a matter of swapping the image — see Docker.

Windows

The Windows distribution ships without ffmpeg, and there is no Lite build for it. With [packager].engine set to auto the native engine is chosen automatically; install ffmpeg and add it to PATH if a compatibility fallback is genuinely required. Otherwise the Windows build matches the complete variant, admin console, database, EPG, and observability included. Installation and service registration are covered in Binary install.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close