Templates
A project template is a small directory of ordinary files (a compose file,
an ant.yaml, an .env.example) plus a template.yaml that declares its
metadata and the values a user can fill in. ant nest new renders one into a
new project folder; the dashboard's Add project → Template does the same
through the shared library.
ant nest templates sync # import the Dokploy catalog
ant nest templates list # (--json)
ant nest templates search postgres # (--tag, --refresh, --limit, --json)
ant nest templates show ackee # metadata and variables (--json)
ant nest new ackee # → ~/.ant-apps/ackee
ant nest new ackee ~/stacks/ackee --group apps # choose folder and group
ant nest new ackee --var HOST_PORT=5433 # set a template variable
ant nest new also takes --app, --target-machine, --force, and --json;
templates sync takes --repo, --ref, and --dir (convert a local checkout
instead of cloning).
The catalog is what you import with ant nest templates sync (the Dokploy
blueprints, below) plus any templates in ~/.ant/templates; listing downloads
nothing.
The Dokploy catalog
ant nest templates sync imports the Dokploy open-source blueprints
(Dokploy/templates, several hundred
stacks) as ant templates:
ant nest templates search postgres # search Dokploy's catalog (cached 24h)
ant nest templates search --tag database
ant nest templates add plausible # fetch one template
ant nest new plausible # fetches it on demand if not local
ant nest templates sync # or import the whole catalog (offline use)
search reads Dokploy's published catalog; new <id> (and templates add)
downloads just that blueprint, converts it, and caches it under
~/.ant/templates-dokploy. You do not need a full sync for one stack. The
dashboard's Add → Template does the same: it lists the whole catalog and
filters it as you type, and downloads a template when you pick it. The catalog
is bundled with ant and cached after a fetch, so the list still works when the
index cannot be reached.
They land in ~/.ant/templates-dokploy and are listed with your own
~/.ant/templates; your own template overrides an imported one with the same
id.
The conversion adapts Dokploy's model to ant's:
- Ports. Dokploy routes through a shared Traefik on the compose network and
services only
exposetheir port. ant's Caddy routes to a host port, so each routed service gets a published loopback port ("3000:3000"); change it if it clashes with something else on the machine. - Variables. Dokploy
${password}values become generated secrets written to the project's.env; other values become defaults. - Domains.
[[config.domains]]become ant deployment domains (a local<app>.localhostby default; add a real domain for a nest). - Config files.
[[config.mounts]]are written underfiles/and the compose's../files/…binds are pointed at them; the loaded file is gitignored because it may hold a generated secret. - Env & secrets.
[config.env]entries (table orenv = […]array) are applied to the stack; a${password}becomes a generated secret variable and${domain}the local host. Values that reference other variables (https://${host}) resolve at instantiation; secrets are never inlined into the compose. - Swarm
deploy:. Compose-honored keys (replicas,resources) are kept,restart_policybecomesrestart, and Swarm-only keys (mode,placement, update/rollback config) are dropped. A top-levelname:and per-servicecontainer_name:are removed, since ant namespaces per project.
Blueprints ant cannot represent (for example a Traefik label with a {{...}}
template, or anything ant's template loader rejects) are skipped, so a bad
blueprint never breaks the catalog. Values that Dokploy composes from other
variables (a URL built from a password) may need a small edit after creation.
Where projects are created
Without a directory argument, a new project goes to ~/.ant-apps/<app>, or
/etc/ant/apps/<app> when ant runs as root (e.g. on a server). Set
ANT_APPS_DIR to override the root. The directory is created on the machine
running ant: --target-machine records a deploy target in ant.yaml; it does
not move the files.
Generated values
Secrets are generated per project and written to the project's .env file with
mode 0600, alongside a .gitignore that keeps it out of git. Compose reads
that file for ${VAR} interpolation, and ant injects it for container
templates that declare env_file: [.env]. The CLI and the dashboard show
generated values once, at creation time.
Databases are marked as such
A template sets the project's kind:
# ant.yaml
app: postgres
kind: database
The dashboard presents a database project without the source-build surfaces
(made-up Dockerfile fields, image-keep counts) while keeping every deploy
feature (environments, domains, volumes, resources) available. A project
without kind is an ordinary app.
Authoring a template
Place a directory in ~/.ant/templates/<id>/. It overrides an imported template
with the same id. The layout:
~/.ant/templates/my-db/
template.yaml # metadata + variable schema (never copied)
docker-compose.yml # rendered into the project
ant.yaml # rendered
.env.example # rendered
template.yaml:
name: My DB
description: A database with a generated password.
kind: database # or app
app: mydb # default app/folder name
run: compose # or container
tags: [database, postgres]
port: 5432 # default port, recorded on the project
resolve: true # resolve {{VAR}} in files at instantiation
variables:
- key: MYDB_USER
label: Database user
default: app
required: false
- key: HOST_PORT
type: port
default: "5432"
- key: MYDB_PASSWORD
generate: password # generated at instantiation
secret: true # written only to .env
A variable's type may be port (validated as a port) or a plain string;
label, required, and secret refine how it is prompted and rendered.
Two substitution syntaxes coexist:
| Syntax | Resolved | Use for |
|---|---|---|
{{KEY}} | at instantiation, inlined into the file | ports, names, ant.yaml fields |
${KEY} | at deploy time, from the generated .env | secrets and any value a user may rotate |
Templates are validated when they load (and by go test ./internal/template):
- the template id must match
^[a-z0-9][a-z0-9._-]*$; ant.yamlis required and must setdeploy.build: none; templates run pre-built images;run:must becontainerorcompose;- the compose file must not use
container_name, a top-levelname:, orexternal: truenetworks/volumes; compose's per-project namespace (-p <app>-<env>) already keeps stacks apart; .envis reserved for ant's generated file, so ship.env.exampleinstead;- a secret variable must use
${KEY}, never{{KEY}}, and must also setgenerate:; - every declared variable must be referenced somewhere;
- the default render must parse and load.
See Deploy for what the generated ant.yaml can do.