Submit an issue View all issues Source
MIR-468

Simplify and clarify deployment configuration system

Done public
phinze phinze Opened Oct 28, 2025 Updated Mar 25, 2026

Problem

Our deployment configuration system answers three key questions but does so through multiple overlapping mechanisms that feel diffuse and inconsistent:

  1. "What command runs your app?" - Answered by: Dockerfile.miren CMD, Procfile, app.toml services.*.command, stackbuild auto-detection, or container defaults
  2. "How many copies simultaneously?" - Answered by: app.toml services.*.concurrency with runtime defaults
  3. "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.toml with [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 $PORT in 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

  1. Short term: Document the current behavior clearly
    • When do you need app.toml vs Procfile vs nothing?
    • What's the precedence order?
  2. 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
  3. 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