Skip to main content

Custom Template Sources Free

Add your own docker-compose service templates from any GitHub repository — they appear alongside Coolify's built-in 200+ one-click services.

Overview​

Coolify ships with 200+ built-in one-click service templates (Ghost, Gitea, Uptime Kuma, n8n, etc.). Custom Template Sources lets you extend this list with your own templates hosted in any GitHub repository — public or private.

  • Same format as Coolify — templates use the exact same YAML structure as built-in templates
  • Seamless integration — custom templates appear in the New Resource page with a small label identifying their source
  • Auto-sync — templates are fetched from GitHub periodically (default: every 6 hours)
  • Safe — after deploying a service, the compose YAML is stored in the database; removing a template source has zero impact on running services

Quick Start​

  1. Create a GitHub repository with a templates/compose/ folder
  2. Add a YAML template file (see Template Format)
  3. In Coolify, go to Settings > Templates
  4. Click + Add Source and enter your repository URL
  5. Click Save & Sync
  6. Go to New Resource — your template now appears in the Services list

Adding a Template Source​

Via the UI​

  1. Navigate to Settings > Templates
  2. Click + Add Source
  3. Fill in:
    • Name — a display name (e.g., "My Company Templates")
    • Repository URL — the GitHub repository URL
    • Branch — the branch to fetch from (default: main)
    • Folder Path — path to the templates folder (default: templates/compose)
    • Auth Token (optional) — a GitHub Personal Access Token for private repositories
  4. Click Save & Sync

Via the API​

curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My Templates",
"repository_url": "https://github.com/myorg/coolify-templates",
"branch": "main",
"folder_path": "templates/compose"
}' \
https://coolify.example.com/api/v1/template-sources

Template Format​

A custom template is a standard docker-compose YAML file with special comment headers that provide metadata.

Metadata Headers​

Add these comment lines at the top of your YAML file, before any YAML content:

# documentation: https://docs.example.com/
# slogan: A brief description of your service.
# tags: tag1,tag2,tag3
# category: self-hosting
# logo: svgs/myservice.svg
# port: 8080
HeaderRequiredDescription
documentationNoURL to the service's documentation
sloganNoShort description shown below the service name (max 80 characters)
tagsNoComma-separated search tags
categoryNoCategory for filtering (e.g., monitoring, cms, ai, development)
logoNoPath to the service logo (relative to repo root, or absolute URL). SVG preferred
portNoPrimary port the service listens on
typeNodatabase or application — overrides automatic classification
ignoreNoSet to true to exclude from the template list

Docker Compose Body​

The rest of the file is a standard docker-compose definition:

# documentation: https://github.com/louislam/uptime-kuma
# slogan: A self-hosted monitoring tool.
# tags: monitoring,status,uptime
# category: monitoring
# logo: svgs/uptime-kuma.svg
# port: 3001

services:
uptime-kuma:
image: louislam/uptime-kuma:2
environment:
- SERVICE_URL_UPTIMEKUMA_3001
volumes:
- uptime-kuma-data:/app/data
healthcheck:
test: ["CMD-SHELL", "extra/healthcheck"]
interval: 5s
timeout: 5s
retries: 10

Environment Variables​

Coolify detects environment variables using ${VARIABLE} syntax and displays them in the UI:

SyntaxBehavior
VARIABLE=hardcodedNot visible in the Coolify UI
VARIABLE=${MY_VAR}Editable in UI, user must provide a value
VARIABLE=${MY_VAR:-default}Editable in UI, falls back to default
VARIABLE=${MY_VAR:?}Required — deployment fails if not set

Magic Variables​

Coolify generates dynamic variables using the pattern SERVICE_<TYPE>_<IDENTIFIER>:

PatternExampleDescription
SERVICE_URL_<NAME>_<PORT>SERVICE_URL_MYAPP_8080Generates the service URL
SERVICE_FQDN_<NAME>_<PORT>SERVICE_FQDN_MYAPP_8080Generates a fully-qualified domain name
SERVICE_USER_<NAME>SERVICE_USER_MYSQLGenerates a random username
SERVICE_PASSWORD_<NAME>SERVICE_PASSWORD_MYSQLGenerates a random password
SERVICE_BASE64_64_<NAME>SERVICE_BASE64_64_TOKENGenerates a 64-character base64 string

Repository Structure​

your-repo/
├── templates/
│ └── compose/
│ ├── service-a.yaml
│ └── service-b.yaml
├── svgs/ # Optional: store logos here
│ ├── service-a.svg
│ └── service-b.svg
└── README.md
  • Template files must have .yaml or .yml extension
  • Only files in the configured folder are scanned (no recursive subdirectories)
  • The template name is derived from the filename: my-service.yaml becomes "My Service"
  • Maximum 500 templates per source, 1MB per template file

Auto-Sync​

All enabled template sources are automatically synced every 6 hours by default. Configure the interval via environment variable:

# Every 6 hours (default)
CORELIX_TEMPLATE_SYNC_FREQUENCY="0 */6 * * *"

# Every hour
CORELIX_TEMPLATE_SYNC_FREQUENCY="0 * * * *"

# Disable auto-sync
CORELIX_TEMPLATE_SYNC_FREQUENCY=

You can also trigger a manual sync from Settings > Templates or via the API:

# Sync one source
curl -X POST -H "Authorization: Bearer $TOKEN" \
https://coolify.example.com/api/v1/template-sources/{uuid}/sync

# Sync all sources
curl -X POST -H "Authorization: Bearer $TOKEN" \
https://coolify.example.com/api/v1/template-sources/sync-all

Source Labels​

Custom templates display a small badge on the service card in the New Resource page, showing which source they came from. This helps distinguish custom templates from built-in ones.

Name Collisions​

When a custom template has the same name as a built-in template:

  • Built-in templates always win — the custom template gets a suffix (e.g., ghost-my-company)
  • Custom-to-custom collisions — both get the source slug suffix

Troubleshooting​

Templates not appearing​

  1. Check that the source is enabled in Settings > Templates
  2. Click Sync to trigger a manual refresh
  3. Check for sync errors — the status badge shows synced, failed, or syncing
  4. Ensure YAML files have a services section — files without it are skipped

Authentication errors​

For private repositories, add a GitHub Personal Access Token with repo scope.

Rate limits​

Unauthenticated GitHub requests are limited to 60/hour. Add a token to get 5,000/hour.