Overriding the App Container Command (and When Not To)
command: lets an environment run Octane with different worker counts — but set it to a one-off task and the container exits immediately.
The gap
Workers and sidecars could always override their image's CMD. The app container itself couldn't — from .neo.yml, per environment, or through neo config generate reading a compose file. That wasn't a decision, just an unfilled case, and it blocked a real one: running Laravel Octane with different worker counts per environment from a shared image.
Using it
command: php artisan octane:frankenphp --workers=4
environments:
dev:
command: php artisan octane:frankenphp --workers=1
Both the string form above and a docker-compose style list are accepted:
command: ["sh", "-lc", "php artisan octane:frankenphp --workers=4"]
The resolved command is persisted to server state, so an --env-only restart (which reuses the existing image) keeps it.
The one rule that matters
A container's command: is its main process — it has to keep running. This is the mistake to know about before you make it:
command: php artisan storage:link # wrong — this exits in milliseconds
That command runs, exits, and takes the container down with it. The deploy fails its health check and rolls back. When this happens, Neo now names command: as the likely cause instead of leaving you with a bare "failed health check":
✗ The container exited on its own. command: is set to "php artisan storage:link".
→ A container's command is its main process — it has to keep running.
→ For one-off setup tasks use release: instead.
The rule of thumb
command: — a long-running process: Octane flags, a different server binary, a custom entrypoint.
release: — one-off tasks that exit: migrations, storage:link, cache warming.
Try it yourself — Neo is free, with every feature unlocked.
Get started free