---
title: "Lite, Core & Full"
description: "Compare the features, size, resource budget, and distribution of Lite, Core, and Full, then choose the right build."
---

> Documentation Index
> Fetch the complete documentation index at: https://kiln.wbxdocs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lite, Core & Full

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 |  |  |  |
| --- | --- | --- | --- |
| 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.

> **Core's “no ffmpeg” is a dependency boundary**
>
> Core does not strip the compatibility code at compile time; the official image simply does not contain an ffmpeg executable. Putting one into a Core container yourself moves that boundary. Lite is the variant that really is trimmed at compile time.

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](/en/guide/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:

```bash
# 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:

```bash
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](/en/start/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.

> **What this data cannot support**
>
> The experiment used small deterministic fixtures, not real bitrates. It cannot support 1080p or 4K throughput rankings, multi-channel concurrency limits, CPU efficiency, time to first frame, or long-run memory stability, and it does not cover the memory and CPU cost of Full actually launching an ffmpeg fallback. Real deployments should run their own end-to-end acceptance and soak tests against the target channels.

### 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:

```bash
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:

```bash
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](/en/start/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](/en/start/binary/).

Source: https://kiln.wbxdocs.com/en/guide/variants/index.mdx
