Skip to content

Custom templates

Organizations can add their own templates next to the catalog. A custom template uses the same format as the catalog: a template.yaml describing the app and its inputs, plus a Docker Compose file.

  1. Open Settings → Templates → Import.
  2. Paste or upload a template bundle (a template.yaml with a compose: key), or enter an https:// URL to fetch it from.
  3. Falak validates it and shows problems line by line. Save.

URL imports: https only, public addresses only, at most 3 redirects, 10-second timeout, 20 fetches per minute.

Custom templates appear in the gallery next to catalog templates. Edit or delete them under Settings → Templates (templates.manage: owners, admins, developers). Each organization can have up to 200.

template.yaml
name: Wiki.js
slug: wikijs
version: 1.0.0
description: Modern wiki on Node.js with PostgreSQL.
category: cms
icon: wikidotjs # a simple-icons key, or ./icon.svg
docs: https://docs.requarks.io
stateful: true # warn when deploying to more than one server
min_memory_mb: 512
popular: false
tags: [wiki, docs]
public:
- service: wiki
port: 3000
inputs:
- key: DB_PASSWORD
type: secret
generate: password(32)
label: Database password
- key: SITE_TITLE
type: string
label: Site title
default: Our wiki
required: false
compose:
services:
wiki:
image: ghcr.io/requarks/wiki:2.5.300
expose: ["3000"]
environment:
DB_TYPE: postgres
DB_HOST: db
DB_USER: wiki
DB_PASS: ${DB_PASSWORD}
DB_NAME: wiki
depends_on: [db]
db:
image: postgres:17.11-alpine
environment:
POSTGRES_USER: wiki
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: wiki
volumes: [wiki-db:/var/lib/postgresql/data]
volumes:
wiki-db:

In the catalog, the Compose file lives next to template.yaml as compose.yaml (plus an optional icon.svg); an import bundle carries it under compose: (as a mapping or a string). Use one or the other, not both.

Key Required Rule
name ✓ Up to 60 characters
slug ✓ ^[a-z0-9][a-z0-9-]{0,49}$
version ✓ Semantic version, e.g. 1.0.0
description ✓ Up to 300 characters
category ✓ automation, analytics, cms, databases, dev-tools, monitoring, storage, communication, ai
icon A simple-icons key ([a-z0-9], up to 64) or ./icon.svg
docs An https:// URL
stateful Boolean; warns on multi-server deploys
min_memory_mb Integer 64–262144
popular Boolean
tags Up to 10 lowercase words (up to 24 characters each)
public ✓ At least one {service, port}
inputs List of inputs (below)
compose ✓* The Compose file (*or a separate compose.yaml)

Unknown keys are errors, so typos never silently drop settings.

Key Meaning
key Variable name, ^[A-Z_][A-Z0-9_]{0,127}$
type string, secret, email, number, boolean, select, domain
label, description, placeholder Form text
default Default value. May contain references like ${{ postgres.DATABASE_URL }} or ${{ falak.url(web) }}
generate secret(n), password(n), hex(n) (n = 8–128) or uuid
options Choices for select
required Default true

Inputs become site variables (secrets encrypted). Generated values are created once when the site is created and never change on redeploy.

Generator Produces
secret(n) n characters from A–Z, a–z, 0–9
password(n) n characters from an unambiguous alphabet with upper case, lower case and digits (URL and dotenv safe)
hex(n) n lowercase hex characters
uuid A random UUID v4

Rendered once, when a site is created from the template:

Placeholder Becomes
${{ falak.url(<service>) }} https://<domain of that public service>
${{ falak.domain(<service>) }} The domain of that public service
${{ falak.site }} The site slug

Compose interpolation (${VAR}) stays Compose-native and reads the site’s variables at deploy time. Besides inputs, FALAK_SITE_ID, FALAK_SERVER_ID, FALAK_DEPLOYMENT_ID and FALAK_RELEASE_ID are available.

A template is rejected when:

  • compose.yaml does not parse, or include/extends are used;
  • a service uses build: (templates must reference published images);
  • an image is missing, interpolated (${…}), untagged or tagged latest (pin a version or a @sha256: digest);
  • a service sets container_name (Falak names containers per site so a template can be deployed twice);
  • a ${VAR} is neither an input nor a Falak variable (use ${VAR:-default} for optional ones);
  • a ${{ … }} in compose.yaml is not a Falak placeholder (variable references belong in input defaults);
  • a public service does not exist or does not expose its port (add expose: ["3000"]);
  • the Compose security policy is violated.

Each of template.yaml and the Compose file may be up to 256 KiB.

On the control plane host, render a catalog template with sample inputs to see what a site would get:

Terminal window
falak-ctl artisan templates:render n8n --domain=falak.test --env-file=/tmp/n8n.env