Docker Compose Plates: Reusable Infrastructure Stacks with kikplate
Infrastructure setup is one of the most repeated tasks in software development. Every new project needs a database, a cache, a message broker, or an observability stack. Teams copy configurations from old projects, adjust port numbers, forget to add health checks, use unofficial images, and eventually end up with inconsistent setups across their environments.
This article walks through a curated collection of twenty Docker Compose plates built for the kikplate template generation system. Each plate is a parameterised, versioned, composable unit that generates a production-ready stack from a single command.
What is kikplate?
kikplate is a developer toolchain for generating project files from versioned, schema-driven templates.
A plate lives on its own Git branch. It defines:
- A typed schema of input variables
- Optional feature modules
- A set of template files
Templates are fetched from GitHub, rendered with the provided values, and written to a local output directory.
Install on macOS and Linux
brew tap kikplate/homebrew-kikplate
brew install --cask kik
Install on Windows
scoop bucket add kikplate https://github.com/kikplate/scoop-bucket.git
scoop install kik
The Plate Format
Every plate in the collection follows the same directory structure:
plate.yaml schema, modules, and file definitions
values.yaml default values for all schema variables
templates/
docker-compose.yml.tmpl main compose template
.env.tmpl secrets template
README.md.tmpl usage documentation
... additional config files where needed
The plate.yaml file acts as the manifest.
Example: the PostgreSQL plate.
name: postgres
owner: kikplate-public
description: PostgreSQL 16 database with optional pgAdmin 4 web interface,
persistent named volumes, health checks, and bridge network isolation.
version: 1.0.0
category: database
tags:
- postgres
- postgresql
- database
- pgadmin
- docker-compose
schema:
projectName:
type: string
default: postgres
postgresVersion:
type: string
default: "16"
postgresUser:
type: string
default: app
postgresDb:
type: string
default: app
postgresPort:
type: int
default: 5432
timezone:
type: string
default: UTC
sharedBuffers:
type: string
default: "128MB"
maxConnections:
type: int
default: 100
pgadminVersion:
type: string
default: "8"
pgadminEmail:
type: string
default: admin@example.com
pgadminPort:
type: int
default: 5050
modules:
pgadmin:
enabled: true
files:
- path: docker-compose.yml
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/postgres/templates/docker-compose.yml.tmpl
- path: .env
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/postgres/templates/.env.tmpl
- path: README.md
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/postgres/templates/README.md.tmpl
Schema
The schema section defines every configurable value, including:
- Type
- Default value
- Validation rules (when applicable)
Modules
The modules section defines optional capabilities that can be enabled or disabled during generation.
Files
The files section specifies every generated output file and the remote template that should be rendered.
values.yaml
The values.yaml file is a flat copy of all schema defaults and serves as the primary customization point.
projectName: "postgres"
postgresVersion: "16"
postgresUser: "app"
postgresDb: "app"
postgresPort: 5432
timezone: "UTC"
sharedBuffers: "128MB"
maxConnections: 100
pgadminVersion: "8"
pgadminEmail: "admin@example.com"
pgadminPort: 5050
modules:
pgadmin:
enabled: true
What Gets Generated
Running:
kik generate kikplate-public/postgres
produces three files.
docker-compose.yml
The Compose file is rendered from the template. Image versions, container names, ports, command flags, network names, and optional services are generated from the provided schema values.
services:
postgres:
image: postgres:16-alpine
container_name: myapp-postgres
restart: unless-stopped
stop_grace_period: 30s
security_opt:
- no-new-privileges:true
env_file:
- .env
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
PGTZ: UTC
command: >
postgres
-c shared_buffers=128MB
-c max_connections=100
-c timezone=UTC
-c log_timezone=UTC
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- db_net
pgadmin:
image: dpage/pgadmin4:8
container_name: myapp-pgadmin
restart: unless-stopped
stop_grace_period: 30s
security_opt:
- no-new-privileges:true
env_file:
- .env
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION: "True"
PGADMIN_LISTEN_PORT: 80
ports:
- "5050:80"
volumes:
- pgadmin_data:/var/lib/pgadmin
depends_on:
postgres:
condition: service_healthy
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- db_net
volumes:
postgres_data:
pgadmin_data:
networks:
db_net:
driver: bridge
.env
Secrets and sensitive values are generated into a separate environment file.
Placeholder values make it obvious what should be changed before a deployment.
POSTGRES_USER=app
POSTGRES_PASSWORD=changeme
POSTGRES_DB=app
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=changeme
README.md
A project-specific README is generated alongside the stack.
The rendered documentation includes:
- Startup instructions
- Service URLs
- Port mappings
- Connection strings
- Operational guidance
All values are generated using the parameters provided during plate generation.
Why Use Plates?
Instead of copying Compose files between projects, teams can generate consistent infrastructure stacks from a controlled source.
Benefits include:
- Versioned infrastructure definitions
- Standardised health checks
- Consistent security settings
- Reusable configuration patterns
- Optional feature modules
- Built-in documentation generation
- Reduced setup time for new projects
- Easier maintenance across teams
Every generated stack follows the same design principles and can be reproduced at any time from its original plate version.
The Collection
The repository currently contains twenty Docker Compose plates organised into five categories.
Each plate defines:
- A service stack
- Schema-driven configuration
- Optional modules
- Generated documentation
- Environment templates
Each row in the collection documents:
- The plate slug
- The generated Docker Compose services
- Available optional modules
This allows teams to quickly select the required infrastructure stack and generate a production-ready environment with a single command.
Database
Backend
DevOps
Security
Other
Architecture and Composition
The diagram below shows all twenty plates and the composition relationships between them. Solid arrows indicate a default-enabled composition. Dashed arrows indicate an optional module.
How Composition Works
Many infrastructure stacks depend on other services. For example, Keycloak typically requires a PostgreSQL database.
Instead of duplicating database definitions, kikplate supports plate composition, allowing one plate to reuse templates from another plate.
The Keycloak plate composes the PostgreSQL plate by referencing its templates directly in plate.yaml.
modules:
postgres:
enabled: true
pgadmin:
enabled: false
files:
- path: docker-compose.yml
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/keycloak/templates/docker-compose.yml.tmpl
- path: docker-compose.postgres.yml
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/postgres/templates/docker-compose.yml.tmpl
condition: modules.postgres.enabled
- path: .env
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/keycloak/templates/.env.tmpl
- path: README.md
template: https://raw.githubusercontent.com/kikplate/docker-compose-plates/keycloak/templates/README.md.tmpl
When modules.postgres.enabled is set to true, kikplate:
- Fetches the PostgreSQL template from the PostgreSQL plate branch.
- Renders it using the values provided to the Keycloak plate.
- Generates a dedicated
docker-compose.postgres.ymlfile. - Includes that generated Compose file in the final deployment.
This approach enables reusable infrastructure building blocks without copying configuration between plates.
Shared Schema
To ensure the PostgreSQL template always receives valid input values, the Keycloak plate includes all PostgreSQL-related variables in its own schema.
schema:
projectName:
type: string
default: keycloak
keycloakVersion:
type: string
default: "24.0"
postgresVersion:
type: string
default: "16"
postgresPort:
type: int
default: 5432
timezone:
type: string
default: UTC
sharedBuffers:
type: string
default: "128MB"
maxConnections:
type: int
default: 100
pgadminVersion:
type: string
default: "8"
pgadminPort:
type: int
default: 5050
pgadminEmail:
type: string
default: admin@example.com
keycloakPort:
type: int
default: 8080
keycloakLogLevel:
type: string
default: INFO
Because all required PostgreSQL variables are available in the schema, the PostgreSQL templates can be rendered independently without requiring any additional configuration.
Docker Compose Includes
The Keycloak Compose template uses Docker Compose's include capability to compose the generated PostgreSQL stack into the final deployment.
{{ if .modules.postgres.enabled }}
include:
- docker-compose.postgres.yml
{{ end }}
services:
keycloak:
image: quay.io/keycloak/keycloak:{{ .keycloakVersion }}
container_name: {{ .projectName }}-keycloak
restart: unless-stopped
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: ${POSTGRES_USER}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
ports:
- "{{ .keycloakPort }}:8080"
depends_on:
postgres:
condition: service_healthy
networks:
- kc_net
- db_net
networks:
kc_net:
driver: bridge
When PostgreSQL is enabled:
-
docker-compose.postgres.ymlis generated. - The Keycloak stack includes it automatically.
- The PostgreSQL service exposes the
db_netnetwork. - The Keycloak container joins
db_net. - Keycloak can connect to PostgreSQL using the hostname
postgres. - Startup order is controlled through health checks and
depends_on.
This creates a loosely coupled but fully integrated deployment.
Generated Output
Generating the Keycloak plate produces the following files:
generated/
├── docker-compose.yml
├── docker-compose.postgres.yml
├── .env
└── README.md
docker-compose.yml
Contains:
- The Keycloak service
- Compose include directives
- Keycloak-specific networking and configuration
docker-compose.postgres.yml
Contains:
- PostgreSQL service
- Persistent volumes
- Health checks
- Logging configuration
-
db_netnetwork
.env
Contains shared credentials used by both services.
POSTGRES_USER=app
POSTGRES_PASSWORD=changeme
POSTGRES_DB=keycloak
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=changeme
README.md
Contains deployment-specific documentation including:
- Startup instructions
- Access URLs
- Port mappings
- Login credentials guidance
Benefits of Composition
Plate composition provides several advantages:
- Reuse existing infrastructure definitions
- Eliminate configuration duplication
- Keep service definitions independent
- Share common variables across related stacks
- Generate modular Docker Compose deployments
- Simplify maintenance and versioning
- Allow optional dependencies through modules
Instead of embedding PostgreSQL directly into the Keycloak plate, the Keycloak plate composes the PostgreSQL plate as a reusable building block. This keeps both plates focused on a single responsibility while still allowing them to work together as a complete deployment.
Composition Examples
The same composition pattern is used throughout the collection.
Examples include:
- WordPress → composes MySQL, optionally Redis.
- n8n → composes PostgreSQL, optionally Redis.
- Grafana and observability stacks → optionally compose PostgreSQL as the backend database.
Each plate remains focused on a single responsibility while reusing infrastructure components from other plates where appropriate.
Generating a Plate
The simplest generation flow uses interactive prompts and accepts default values.
kik generate kikplate-public/postgres
Generate from a Values File
To avoid prompts entirely, provide a values file.
kik generate kikplate-public/postgres -f values.yaml
Every plate includes a values.yaml file containing all schema variables with default values.
Teams typically:
- Generate a values file.
- Customise it for their environment.
- Commit it into source control.
- Regenerate infrastructure at any time from the committed values.
This makes infrastructure reproducible and eliminates manual configuration.
Override Individual Values
Specific values can be overridden directly on the command line.
kik generate kikplate-public/postgres \
--set projectName=myapp \
--set postgresPort=5433
Generate into a Specific Directory
Generated files can be written to a dedicated location.
kik generate kikplate-public/postgres \
--output-dir ./infra/postgres
Generate Directly to a Repository
Generated output can also be pushed directly into a remote repository.
kik generate kikplate-public/postgres \
-f values.yaml \
--repo https://github.com/yourorg/infra.git
Consistency Across Every Plate
Regardless of the service being provisioned, every plate follows the same operational and security standards.
Secrets Management
No passwords or secrets are embedded in templates.
Generated secrets are written to a separate .env file with placeholder values.
POSTGRES_PASSWORD=changeme
REDIS_PASSWORD=changeme
Developers replace these values before starting the stack.
Health Checks
Every stateful service defines a health check.
Dependent services wait until dependencies become healthy before starting.
depends_on:
postgres:
condition: service_healthy
This guarantees a reliable startup sequence during:
docker compose up
Logging
Every service uses the Docker json-file logging driver.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Benefits include:
- Log rotation
- Predictable disk usage
- Consistent behaviour across stacks
Network Isolation
Each plate defines its own named Docker bridge network.
networks:
app_net:
driver: bridge
Services communicate only within their assigned network.
When plates are composed together, the dependent service joins the required networks to enable controlled communication between components.
Security Options
All containers run with:
security_opt:
- no-new-privileges:true
Additional Linux capabilities are not granted unless the application explicitly requires them.
For example:
cap_add:
- IPC_LOCK
is included for Vault because its functionality depends on memory locking.
Graceful Shutdown
Every container defines a shutdown grace period.
stop_grace_period: 30s
This allows databases, queues, and brokers to:
- Complete pending writes
- Flush data safely
- Exit cleanly
before container termination.
Official Images
Every plate uses official vendor-maintained container images.
Examples include:
postgresmysqlredisgrafanaprometheusquay.io/keycloak/keycloak
Images are version-pinned through schema defaults and can be overridden at generation time.
No community-maintained wrappers or floating latest tags are used.
How Teams Use This
Small Development Teams
A backend team starts a new service and requires:
- PostgreSQL
- Redis
Without automation, the team typically:
- Copies an old
docker-compose.yml. - Adjusts service names.
- Changes ports.
- Updates image versions.
- Fixes broken health checks.
- Troubleshoots startup issues.
With kikplate:
kik generate kikplate-public/postgres \
-f postgres-values.yaml \
--output-dir ./infra/postgres
kik generate kikplate-public/redis \
-f redis-values.yaml \
--output-dir ./infra/redis
Two commands produce two standardised infrastructure stacks.
The generated configurations are:
- Current
- Version-controlled
- Health-checked
- Secure by default
- Reproducible
Platform Teams
Platform engineering teams often need to standardise infrastructure across dozens of services.
A common approach is to maintain approved values files.
When a new service is created, developers:
- Select an approved plate.
- Generate infrastructure using the approved values file.
- Commit the generated output alongside their application.
This ensures every service begins with infrastructure aligned to organisational standards.
Updating Existing Deployments
When a plate receives updates such as:
- New image versions
- Security improvements
- Additional configuration options
- Operational enhancements
teams simply regenerate the files.
kik generate kikplate-public/postgres -f values.yaml
The generated changes can be reviewed using normal source control workflows.
The plate remains the single source of truth for infrastructure configuration.
Repository Structure
The Docker Compose Plates collection is hosted at:
Docker Compose Plates Repository
The repository uses a branch-per-plate model.
Individual Plate Branches
Each plate resides on its own branch.
Examples:
postgres
redis
mysql
keycloak
wordpress
n8n
grafana
Each branch contains:
plate.yaml
values.yaml
templates/
plate.yaml
Defines:
- Schema
- Modules
- Template files
- Metadata
values.yaml
Contains default values for all schema variables.
templates/
Contains the source templates that are rendered during generation.
Examples:
templates/
├── docker-compose.yml.tmpl
├── .env.tmpl
├── README.md.tmpl
└── additional configuration templates
Main Branch
The main branch contains:
- Documentation
- Guides
- The plate catalogue
- Repository metadata
It acts as the public entry point for the collection.
All Branch
The all branch contains every plate as a subdirectory.
all/
├── postgres/
├── redis/
├── keycloak/
├── wordpress/
├── grafana/
└── ...
This branch exists primarily for:
- Cross-plate development
- Local testing
- Refactoring shared functionality
- Reviewing the complete collection in a single working tree
Summary
Docker Compose Plates turns infrastructure configuration from a copy-and-paste exercise into a repeatable generation process.
By combining:
- Typed schemas
- Versioned templates
- Optional modules
- Plate composition
- Standardised operational practices
teams can generate production-ready infrastructure stacks in seconds while maintaining consistency across every environment and every project.






Top comments (0)