Core concepts
Five ideas cover everything deckctl does.
Sources
Section titled “Sources”A source is a place templates live. There are two types:
| Type | What it points at | Cached? |
|---|---|---|
local | A directory on your filesystem | No — read directly from disk |
gitlab | A group on gitlab.com or a self-hosted instance | Yes |
Sources are named, and every template command takes --source <name>. They are
stored in ~/.config/deckctl/config.yaml and managed with
deckctl source add/list/get/remove. Secrets are never written to that file —
GitLab tokens are referenced by environment variable name via token_env.
See Configuring sources.
Templates
Section titled “Templates”A template is a directory of files.
- On a local source, every immediate subdirectory containing a
deckctl.yamlis a template. Directories without one are ignored. - On a GitLab source, every non-archived project in the configured group is a template, and its files sit at the project root.
The sidecar
Section titled “The sidecar”The sidecar is the file that turns a directory into a template. It declares the variables the template expects, the Jinja2 delimiters to use, and which filename suffixes mean “render me”.
deckctl reads two sidecar formats:
| File | Format |
|---|---|
deckctl.yaml | Native — see the sidecar reference |
copier.yml | Copier — translated on the fly |
Under the default --sidecar-format auto, a deckctl.yaml wins if both are
present. See Copier compatibility.
Render vs. copy
Section titled “Render vs. copy”Whether a file is rendered through Jinja2 or copied verbatim is decided by its filename suffix, never by sniffing its content:
| Source file | Result | Output file |
|---|---|---|
main.go.tpl | Rendered, suffix stripped | main.go |
values.yaml.j2 | Rendered, suffix stripped | values.yaml |
LICENSE | Copied byte-for-byte | LICENSE |
media/logo.png | Copied byte-for-byte | media/logo.png |
The default suffix list is .tpl, .tmpl, .jinja, .j2, overridable per
template with template_suffixes.
This is deliberate: it is deterministic, it is binary-safe, and it means a Helm
chart’s literal {{ .Values.x }} survives untouched as long as you don’t add a
suffix to the file. When you do need to render a file that already contains
{{ }}, change the delimiters instead — see
Custom delimiters.
Variables
Section titled “Variables”Variables are declared in the sidecar with an optional type, default,
description and (for choice) a list of allowed values. At apply time each one
resolves in this order:
--var key=valueon the command line — always wins- The
defaultfrom the sidecar - An interactive prompt
deckctl template variables <name> prints the whole declared surface without
applying anything. See Variables and prompting.
The cache
Section titled “The cache”Templates fetched from GitLab are extracted into ~/.cache/deckctl/, keyed by
<source>/<template>/<ref>. On the next apply deckctl reuses the cached copy if
its last freshness check is within the TTL (1 hour by default); otherwise it
sends a conditional request with the stored ETag, and only downloads bytes if
the server says something actually changed.
Local sources never cache — there is nothing to fetch.
See Caching.
History
Section titled “History”Every successful template apply writes a record — timestamp, template, source,
output path and the resolved variables — into a bbolt
database at ~/.config/deckctl/history.db. Read it back with
deckctl history list, wipe it with deckctl history clear.
Dry runs are not recorded.
Putting it together
Section titled “Putting it together”deckctl template apply go-service ./out --source work --tag v1.2.3 │ ├─ resolve source "work" from config.yaml ├─ GitLab source → list tags, pick v1.2.3 ├─ cache hit for work/go-service/v1.2.3 within TTL? → reuse │ └─ else conditional GET (ETag) → 304 reuse, or 200 re-extract ├─ detect sidecar format (deckctl.yaml → native, copier.yml → copier) ├─ resolve variables: --var > default > prompt ├─ walk the tree: suffix → render through gonja, no suffix → copy └─ write history record