Skip to content

Configuration Schema

Complete reference for the loko.yaml configuration file schema. All fields are sourced directly from the Pydantic models in loko/config.py.

name: "dev-me" # required
provider: kind # optional, default: "kind"
runtime: docker # optional, default: "docker"
expand-env-vars: true # optional, default: true
plugins: # optional
enabled: [...]
disabled: [...]
cluster: # required
nodes:
workers: 0
network: # required
ip: "192.168.0.10"
domain: "dev.me"
registry: # optional, has defaults
enabled: true
components: # optional, has defaults
ingress-controller:
dashboard: false
metrics-server:
enabled: false
tunnel: # optional, has defaults
enabled: true
workloads: # required
system: []
user: []
gitops: # optional, has defaults
enabled: false
provider: fluxcd

Top-level fields:

FieldTypeRequiredDefaultDescription
namestringYesEnvironment name. Must be a valid Kubernetes name (lowercase alphanumeric + hyphens).
providerstringNo"kind"Cluster provider.
runtimestringNo"docker"Container runtime.
expand-env-varsboolNotrueExpand ${VAR} references in config values.
pluginsobjectNonullPlugin configuration (see below).
clusterobjectYesCluster configuration.
networkobjectYesNetwork and DNS configuration.
registryobjectNo(defaults)In-cluster OCI registry.
componentsobjectNo(defaults)System components (ingress, metrics).
tunnelobjectNo(defaults)HAProxy tunnel for TCP port forwarding.
workloadsobjectYesWorkload definitions.
gitopsobjectNo(defaults)GitOps integration.

network:
ip: "192.168.0.10" # required
domain: "dev.me" # required
# dns-port is auto-selected from non-privileged ports (1024–32767), preferring 5453
lb-ports: # optional
http: 80
https: 443
port-overrides: # optional
forgejo: [3000]
FieldTypeRequiredDefaultDescription
ipstringYesHost IP address. Cannot be a loopback address.
domainstringYesBase domain (e.g. "dev.me"). Must be a valid FQDN.
dns-portint|nullNoautodnsmasq host port, auto-selected from non-privileged ports (1024–32767), preferring 5453. Rarely needs to be set manually.
lb-ports.httpintNo80Load balancer HTTP port.
lb-ports.httpsintNo443Load balancer HTTPS port.
port-overridesdictNo{}Per-workload TCP port overrides. Keys are workload names, values are lists of ports.

cluster:
kubernetes-version: null # optional
api-port: null # optional
kubernetes: # optional
api-port: null
image: null
tag: null
nodes: # required
workers: 0
labels: # optional
control-plane:
my-label: "value"
worker:
my-label: "value"
individual:
node-name:
my-label: "value"
scheduling: # optional
control-plane:
isolate-internal-components: true

cluster fields:

FieldTypeRequiredDefaultDescription
kubernetes-versionstring|nullNonullKubernetes version for the Kind node image.
api-portint|nullNonullKubernetes API server port on the host.
kubernetes.api-portint|nullNonullAlternative API port setting (inside kubernetes block).
kubernetes.imagestring|nullNonullCustom Kind node image name.
kubernetes.tagstring|nullNonullCustom Kind node image tag.
nodes.workersintYesNumber of worker nodes. 0 means workloads run on the control plane.
nodes.labels.control-planedictNo{}Labels applied to control-plane nodes.
nodes.labels.workerdictNo{}Labels applied to all worker nodes.
nodes.labels.individualdict|nullNonullLabels for individual nodes by name.
nodes.scheduling.control-plane.isolate-internal-componentsboolNotrueIsolate loko system components to the control-plane node.

Workloads are defined as two lists: system (catalog workloads like forgejo, postgres) and user (custom workloads with explicit Helm config).

workloads:
internal-namespace: loko-components # optional
system-namespace: loko-system # optional
user-namespace: loko-user # optional
use-presets: true # optional
helm-repositories: # optional
- name: groundhog2k
url: https://groundhog2k.github.io/helm-charts/
oci: false
system:
- name: forgejo
enabled: true
namespace: loko-system # optional, overrides system-namespace
storage: 5Gi # optional
ports: [3000, 2222] # optional
user:
- name: my-app
enabled: true
namespace: my-namespace
depends-on: [forgejo]
config:
chart: my-org/my-app
version: "1.2.3"
values:
replicaCount: 2

workloads top-level fields:

FieldTypeRequiredDefaultDescription
internal-namespacestringNo"loko-components"Namespace for internal loko components.
system-namespacestringNo"loko-system"Default namespace for system workloads.
user-namespacestringNo"loko-user"Default namespace for user workloads.
use-presetsboolNotrueApply catalog preset values globally. Can be overridden per workload.
helm-repositorieslistNo[]Additional Helm repositories to register.
systemlistNo[]Catalog workload entries.
userlistNo[]Custom workload entries (require explicit config).

helm-repositories item fields:

FieldTypeRequiredDefaultDescription
namestringYesRepository alias.
urlstringYesRepository URL.
ociboolNofalseWhether this is an OCI registry.

Workload item fields (applies to both system and user lists):

FieldTypeRequiredDefaultDescription
namestringYesWorkload name. Lowercase alphanumeric + hyphens, 1–63 chars.
enabledboolYesWhether to deploy this workload.
use-presetsbool|nullNonullPer-workload preset override. null inherits the global use-presets setting.
namespacestring|nullNonullKubernetes namespace. Falls back to system-namespace or user-namespace.
portslist[int]|nullNonullTCP ports to expose via the tunnel.
storagestring|nullNonullPersistent volume size (Kubernetes format, e.g. "10Gi").
depends-onlist[string]|nullNonullWorkload names this workload depends on (deploy order).
configobject|nullNonullHelm chart config. Required for user workloads; optional for system workloads (catalog provides defaults).

config (WorkloadHelmConfig) fields:

FieldTypeRequiredDefaultDescription
chartstringYesHelm chart name (e.g. "groundhog2k/postgres").
versionstringYesChart version.
valuesdict|nullNonullHelm values to pass at install time.
repo.namestring|nullNonullHelm repo alias (if not already registered).
repo.urlstring|nullNonullHelm repo URL.
repo.refstring|nullNonullGit ref (for type: git repos).
repo.typestringNo"helm"Repository type: "helm" or "git".

In-cluster OCI registry (Zot), available at <registry.name>.<network.domain>.

registry:
enabled: true # optional, default: true
name: cr # optional, default: "cr"
storage: 10Gi # optional, default: "10Gi"
version: null # optional
mirroring:
enabled: true
sources:
- name: docker_hub
enabled: true
- name: quay
enabled: true
- name: ghcr
enabled: true
- name: k8s_registry
enabled: true
- name: mcr
enabled: true
scanning:
enabled: false
interval: 24h
FieldTypeRequiredDefaultDescription
enabledboolNotrueEnable the in-cluster registry.
namestringNo"cr"Registry subdomain prefix. Must be a valid DNS label.
storagestringNo"10Gi"Registry storage size (Kubernetes format).
versionstring|nullNonullChart version override. Uses catalog default if null.
mirroring.enabledboolNotrueEnable pull-through mirroring.
mirroring.sourceslistNo(all 5 enabled)Mirror sources to enable.
mirroring.sources[].namestringYesSource name: docker_hub, quay, ghcr, k8s_registry, mcr.
mirroring.sources[].enabledboolNotrueWhether this mirror source is active.
scanning.enabledboolNofalseEnable Zot CVE scanning (Trivy-backed) via search.cve.
scanning.intervalstringNo"24h"Trivy database update interval (for example 12h, 24h).

System components installed into the cluster.

components:
ingress-controller:
dashboard: false # optional, default: false
version: null # optional
dnsmasq:
version: null # optional
metrics-server:
enabled: false # optional, default: false
version: null # optional
FieldTypeRequiredDefaultDescription
ingress-controller.dashboardboolNofalseEnable the Traefik dashboard.
ingress-controller.versionstring|nullNonullChart version override.
dnsmasq.versionstring|nullNonulldnsmasq image version override.
metrics-server.enabledboolNofalseEnable the Kubernetes metrics server.
metrics-server.versionstring|nullNonullChart version override.

HAProxy tunnel container that forwards TCP ports from the host into the Kind node network, allowing workload ports to be added or removed without recreating the cluster.

tunnel:
enabled: true # optional, default: true
bind-address: null # optional, default: null (auto-detected from network.ip)
FieldTypeRequiredDefaultDescription
enabledboolNotrueEnable the HAProxy tunnel.
bind-addressstring|nullNonullHost address to bind. If null, auto-detected from network.ip.

Controls which LoKO plugins are active for this environment.

plugins:
enabled: # whitelist mode
- credential_injection
- forgejo_runner
disabled: # blacklist mode
- link_resolver
config: # per-plugin configuration
forgejo_runner:
timeout: 60
FieldTypeRequiredDefaultDescription
enabledlist[string]|nullNonullWhitelist: only these plugins will run. Mutually exclusive with blacklisted names.
disabledlist[string]|nullNonullBlacklist: these plugins will not run.
configdict|nullNonullPlugin-specific configuration keyed by plugin name.

GitOps integration settings. Normally written automatically by loko gitops init and loko gitops destroy.

gitops:
enabled: false # default: false
provider: fluxcd # default: "fluxcd"
forgejo:
org: null # default: null
FieldTypeRequiredDefaultDescription
enabledboolNofalseWhether GitOps is initialized for this environment.
providerstringNo"fluxcd"GitOps provider: "fluxcd" or "argocd".
forgejo.orgstring|nullNonullForgejo organization to own the GitOps repo. If null, the authenticated user’s personal account is used.

See the GitOps User Guide for full details.


name: dev-me
network:
ip: "192.168.0.10"
domain: "dev.me"
cluster:
nodes:
workers: 0
registry:
enabled: true
name: cr
storage: 10Gi
components:
ingress-controller:
dashboard: false
metrics-server:
enabled: false
tunnel:
enabled: true
workloads:
use-presets: true
system:
- name: postgres
enabled: true
storage: 10Gi
- name: forgejo
enabled: true
storage: 5Gi
ports: [3000, 2222]
user: []
gitops:
enabled: false
provider: fluxcd
forgejo:
org: null

YAML keys use kebab-case, which maps to Python snake_case in the models:

expand-env-vars: true # → expand_env_vars
dns-port: 5453 # → dns_port
ingress-controller: ... # → ingress_controller
use-presets: true # → use_presets

When expand-env-vars: true (the default), ${VAR} references are expanded:

network:
ip: "${HOST_IP}"
enabled: true
enabled: false