Simplify and clarify deployment configuration system
Problem
Our deployment configuration system answers three key questions but does so through multiple overlapping mechanisms that feel diffuse and inconsistent:
- "What command runs your app?" - Answered by: Dockerfile.miren CMD, Procfile, app.toml services.*.command, stackbuild auto-detection, or container defaults
- "How many copies simultaneously?" - Answered by: app.toml services.*.concurrency with runtime defaults
- "What port for HTTP?" - Answered by: app.toml config.port (default: 3000)
Current Issues
1. The "Service Exists" Problem (recently fixed in #279)
- Services needed explicit commands OR Procfile entries OR app.toml entries to "exist"
- Dockerfile-based apps (like uptime-kuma) with only concurrency config failed to deploy
- Bug: service collection logic didn't include services with only concurrency settings
2. Zero-Config Not Actually Zero
- Stackbuild provides zero-config build, but not zero-config runtime
- Dockerfile.miren deployments get NO services by default
- Must explicitly add
.miren/app.tomlwith[services.web.concurrency]even if container has proper CMD
3. "web" is Magic but Undocumented
- "web" service gets special auto-scaling defaults (auto mode, 10 req/instance)
- Other service names get fixed mode, 1 instance
- Nothing explains this convention or when you need to define services
4. Procfile is Build-time, Not Runtime
- Procfile commands are read during build to define services
- We don't actually use Procfile for process management
- It's just a way to declare service names + commands
5. Port Configuration Semi-Orphaned
- Defaults to 3000 (reasonable)
- Only configurable via app.toml
- Stackbuild stacks hardcode
$PORTin entrypoints but don't set it
Configuration Precedence (Current State)
Build Method Selection:
1. .miren/app.toml [build.dockerfile]
2. Dockerfile.miren (in project root)
3. Auto-detection (Ruby/Python/Node/Bun/Go via stackbuild)
4. ❌ ERROR: "no supported stack detected"
Service Command Resolution:
1. .miren/app.toml [services.NAME.command]
2. Procfile (NAME: command)
3. Stackbuild-generated entrypoint
4. Container default CMD/ENTRYPOINT
Service Concurrency:
1. .miren/app.toml [services.NAME.concurrency]
2. Build-time defaults:
- "web" → auto (10 req/inst, 15m delay)
- others → fixed (1 instance)
Proposed Improvements
A. True Zero-Config for Simple Cases
Make this work with ZERO config files:
# Scenario 1: Dockerfile with CMD
echo 'FROM node:20
CMD ["npm", "start"]' > Dockerfile.miren
miren deploy # Should just work!
Implementation: Auto-create "web" service when Dockerfile or stackbuild is used but no services are defined
B. Make Service Discovery Smarter
// Improved service detection logic
services := []string{}
// 1. Explicit services from app.toml
for name := range appConfig.Services {
services = append(services, name)
}
// 2. Procfile services
for name := range procfile {
if !contains(services, name) {
services = append(services, name)
}
}
// 3. If we have a container with CMD/ENTRYPOINT but no services yet
if len(services) == 0 && (hasDockerfile || hasStackbuild) {
// Default to "web" service
services = append(services, "web")
}
// 4. Apply defaults
applyDefaults(services)
C. Consolidate Documentation Story
Create a clear hierarchy users can understand:
Level 1: Zero Config (for 80% of apps)
Just `miren deploy` - we figure it out
- Detects language, builds appropriately
- Creates "web" service with smart auto-scaling
- Uses port 3000
Level 2: Basic Config (when you need control)
# .miren/app.toml - only override what you need
[services.web.concurrency]
mode = "fixed"
num_instances = 2
Level 3: Multi-Service Apps
[services.web.concurrency]
mode = "auto"
requests_per_instance = 100
[services.worker]
command = "bundle exec sidekiq"
[services.worker.concurrency]
mode = "fixed"
num_instances = 3
D. Improve Error Messages
Instead of: service "web" not found in version config
Provide:
No services configured for this deployment.
Miren needs to know what processes to run. Add a .miren/app.toml:
[services.web.concurrency]
mode = "fixed"
num_instances = 1
Or create a Procfile:
web: <your start command>
Learn more: https://docs.miren.dev/services
Recommended Next Steps
- Short term: Document the current behavior clearly
- When do you need app.toml vs Procfile vs nothing?
- What's the precedence order?
- Medium term: Implement "web" service auto-creation (#279 fixes the build-time bug, but we still need auto-creation)
- If Dockerfile.miren or stackbuild, automatically create "web" service
- Even without Procfile or app.toml
- Long term: Procfile native support or deprecation
- Either use Procfile for runtime process management
- Or deprecate it in favor of app.toml services
Related
- #279 - Fix for services with only concurrency config
- Stackbuild package:
pkg/stackbuild/stackbuild.go - Build server:
servers/build/build.go - Service config resolution:
appconfig/appconfig.go