You can extend FlatRun with custom templates for your own applications or frequently deployed stacks. Custom templates work exactly like built-in templates.
Template Location
Custom templates are stored in the .flatrun/templates directory within your deployments path:
/var/flatrun/deployments/
└── .flatrun/
└── templates/
├── my-custom-app/
│ ├── metadata.yml
│ └── docker-compose.yml
└── my-stack/
├── metadata.yml
└── docker-compose.yml Template Structure
Each template requires two files:
metadata.yml
Describes the template and its options:
id: my-custom-app
name: My Custom Application
description: A custom application template for my team
category: applications
icon: pi-code
logo: /logos/my-app.svg
priority: 10
container_port: 3000
mount_points:
- id: app
label: Application
path: /app
description: Mount the entire application
- id: data
label: Data Directory
path: /app/data
description: Mount only the data directory
files:
- path: .env
template: env.tmpl docker-compose.yml
The compose file with variable placeholders:
version: "3.8"
services:
app:
image: my-registry/my-app:latest
container_name: ${NAME}-app
ports:
- "${PORT}:3000"
environment:
NODE_ENV: production
DATABASE_URL: mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:3306/${DB_NAME}
volumes:
- ./app:/app
networks:
- default
- proxy
- database
restart: unless-stopped
networks:
proxy:
external: true
database:
external: true Metadata Fields
| Field | Required | Description |
|---|---|---|
id | Yes | Unique identifier for the template |
name | Yes | Display name |
description | Yes | Short description |
category | Yes | Category: applications, frameworks, runtimes, databases, infrastructure, basic |
icon | No | PrimeIcons class (e.g., pi-globe) |
logo | No | Path to logo image |
priority | No | Sort order (lower = first) |
container_port | No | Default container port |
mount_points | No | Available mount options |
files | No | Additional files to generate |
Variable Substitution
Use these variables in your docker-compose.yml:
| Variable | Description |
|---|---|
${NAME} | Deployment name |
${PORT} | Assigned external port |
${DOMAIN} | Configured domain name |
${DB_HOST} | Database host |
${DB_PORT} | Database port |
${DB_NAME} | Database name |
${DB_USER} | Database username |
${DB_PASSWORD} | Database password |
Mount Points
Mount points define what parts of the container can be persisted to the host. Each mount point has:
mount_points:
- id: unique_id # Used in API calls
label: Display Name # Shown in UI
path: /container/path
description: Help text for users Users can select which mount points to use when deploying.
Generated Files
You can generate additional configuration files during deployment using templates:
files:
- path: .env
template: env.tmpl
- path: config/app.json
template: app-config.json.tmpl Create template files in your template directory:
# templates/my-app/env.tmpl
APP_NAME=${NAME}
APP_URL=https://${DOMAIN}
DB_CONNECTION=mysql
DB_HOST=${DB_HOST}
DB_DATABASE=${DB_NAME}
DB_USERNAME=${DB_USER}
DB_PASSWORD=${DB_PASSWORD} Infrastructure Templates
To create a template for infrastructure services (databases, proxies, etc.), set type: infrastructure:
id: my-cache
name: My Cache Server
description: Custom caching solution
category: infrastructure
type: infrastructure
container_port: 6380 Testing Templates
- Create your template in
.flatrun/templates/ - Refresh templates via the API or UI
- Deploy a test instance
- Verify all variables are substituted correctly
- Test the deployed application
# Refresh templates
curl -X POST "http://localhost:8090/api/templates/refresh" \
-H "Authorization: Bearer $TOKEN"
# Check your template appears
curl -X GET "http://localhost:8090/api/templates" \
-H "Authorization: Bearer $TOKEN" | jq '.[] | select(.id == "my-custom-app")' Example: Full-Stack Template
A complete example for a Node.js app with Redis:
metadata.yml
id: node-redis-app
name: Node.js + Redis
description: Node.js application with Redis caching
category: frameworks
icon: pi-server
priority: 5
container_port: 3000
mount_points:
- id: app
label: Application Code
path: /app
description: Mount your Node.js application
- id: logs
label: Logs
path: /app/logs
description: Mount only log files
files:
- path: .env
template: env.tmpl docker-compose.yml
version: "3.8"
services:
app:
image: node:20-alpine
container_name: ${NAME}-app
working_dir: /app
command: npm start
ports:
- "${PORT}:3000"
environment:
NODE_ENV: production
REDIS_URL: redis://redis:6379
volumes:
- ./app:/app
depends_on:
- redis
networks:
- default
- proxy
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: ${NAME}-redis
volumes:
- redis_data:/data
networks:
- default
restart: unless-stopped
volumes:
redis_data:
networks:
proxy:
external: true env.tmpl
NODE_ENV=production
PORT=3000
REDIS_URL=redis://redis:6379
APP_NAME=${NAME} Best Practices
- Unique IDs — Use descriptive, unique template IDs
- Good Descriptions — Write clear descriptions for mount points
- Default Ports — Use standard ports for your applications
- Networks — Include proxy and database networks as needed
- Restart Policy — Always set
restart: unless-stopped - Version Control — Keep templates in version control