Configuration
Complete reference for fuku.yaml – services, tiers, profiles, and more.
Generate a config template with fuku init, or create fuku.yaml manually in your project root.
Service definitions
Each service is defined with a name, directory, and optional settings:
services:
backend:
dir: backend # Path to service directory
command: go run cmd/main.go # Custom start command (optional)
tier: platform # Startup tier (optional)
readiness: # Health check (optional)
type: http
url: http://localhost:8080/health
timeout: 30s
interval: 500ms
logs: # Log output filter (optional)
output: [stdout, stderr]
watch: # Hot-reload config (optional)
include: ["**/*.go"]
ignore: ["**/*_test.go"]
shared: ["pkg/common"]
debounce: 1s | Field | Description |
|---|---|
dir | Path to the service directory |
command | Custom start command (default: make run, which requires a Makefile with a run target in the service directory). Runs via sh -c, so shell features like pipes and env vars work |
tier | Startup tier for ordering. Services without a tier go to the default tier (runs last) |
readiness | Health check configuration (see Readiness Checks) |
logs.output | Output streams to capture: stdout, stderr, or both (default: both) |
watch | Hot-reload file watching configuration (see Hot-Reload) |
Tiers
Tiers control startup ordering. Services in earlier tiers start (and become ready) before later tiers begin. The order is determined by the first occurrence of each tier name in your config.
Common tier naming pattern:
- foundation – core services (auth, config, gateway)
- platform – business logic services
- edge – client-facing services
Key points:
- Tier order is defined by first appearance in the YAML file
- Services within each tier are sorted alphabetically by name
- Services without a tier are placed in a
defaulttier that runs last - Tier names are case-insensitive and whitespace is trimmed
- You can use any tier names you want –
infrastructure,middleware,api,frontend, etc.
Profiles
Profiles group services for batch operations:
defaults:
profiles: [default] # Profiles used when no profile is specified
profiles:
default: "*" # All services
backend: [auth, backend] # Named list of services "*"– selects all defined services- A list of service names – selects only those services
- The
defaults.profilesarray controls which profiles run when you just typefuku
Concurrency
concurrency:
workers: 5 # Max concurrent service starts (default: 5) Controls how many services can start in parallel within a single tier.
Retry
retry:
attempts: 3 # Max retry attempts (default: 3)
backoff: 500ms # Initial backoff duration (default: 500ms) Log Streaming
logs:
buffer: 1000 # Broadcast channel depth for socket log streaming (default: 1000)
history: 5000 # Number of recent log messages kept in memory for replay (default: 5000) Logging
logging:
format: console # "console" or "json"
level: info # debug, info, warn, error Server
Built-in REST API for external control. Disabled by default. When server.listen is set, server.auth.token is required. Probes (/api/v1/live, /api/v1/ready) are unauthenticated; all other endpoints require a bearer token.
server:
listen: "127.0.0.1:9876" # TCP address to bind (must be loopback)
auth:
token: "my-dev-token" # Bearer token for authentication Local overrides
Create fuku.override.yaml (or fuku.override.yml) next to your base config to add local customizations without modifying the shared project config. Override files are typically .gitignored.
services:
api:
command: "dlv debug ./cmd/main.go" # override start command
watch:
include: ["*.templ"] # appended to base includes
debug-tool:
dir: tools/debug # add a local-only service
logging:
level: debug # override log level Merge Rules
| Type | Behavior |
|---|---|
| Scalar | Override replaces base |
| Map | Deep merge recursively (base key order preserved) |
| Array | Override items appended after base items (no deduplication) |
| Null | Removes the key from merged config (e.g. watch: null) |
| Mismatched types | Override replaces base |
Important Notes
- Override loading is automatic when using default config discovery (
fuku.yaml/fuku.yml) - Explicit
--configdisables override loading entirely - An override file without a base config is ignored
- Null removal applies to the merged YAML – some removed keys may still have runtime defaults (e.g.
logging: nullstill gets default log level) - If both
fuku.override.yamlandfuku.override.ymlexist,.yamlwins
YAML anchors
Use YAML anchors (&) and merge keys (<<: *) to avoid repeating common configuration. Top-level keys prefixed with x- are ignored by fuku and serve as anchor definitions.
x-readiness-http: &readiness-http
type: http
timeout: 30s
interval: 500ms
x-watch: &watch
include: ["**/*.go"]
ignore: ["**/*_test.go"]
debounce: 1s
services:
api:
dir: ./api
readiness:
<<: *readiness-http
url: http://localhost:8080/health
watch:
<<: *watch Full example
version: 1
x-readiness-http: &readiness-http
type: http
timeout: 30s
interval: 500ms
x-readiness-log: &readiness-log
type: log
pattern: "Service ready"
timeout: 30s
x-logs: &logs
output: [stdout, stderr]
x-watch: &watch
include: ["**/*.go"]
ignore: ["**/*_test.go"]
shared: ["pkg/common"]
debounce: 1s
services:
auth:
dir: auth
tier: foundation
command: go run cmd/main.go
readiness:
<<: *readiness-http
url: http://localhost:8081/health
backend:
dir: backend
tier: platform
command: go run cmd/main.go
readiness:
<<: *readiness-http
url: http://localhost:8080/health
logs:
<<: *logs
watch:
<<: *watch
web:
dir: frontend
tier: edge
readiness:
<<: *readiness-http
url: http://localhost:3000/health
defaults:
profiles: [default]
profiles:
default: "*"
backend: [auth, backend]
concurrency:
workers: 5
retry:
attempts: 3
backoff: 500ms
logs:
buffer: 1000
history: 5000
logging:
format: console
level: info
server:
listen: "127.0.0.1:9876"
auth:
token: "my-dev-token"