Deploying Laravel without hand-writing a queue worker config
Most of what’s annoying about hosting a real Laravel app isn’t Laravel’s fault — it’s that a typical host wants its own config file, its own queue-worker process definition, and its own copy of whatever .env.example already states. The actual information needed to run the app correctly already exists in the repo; the hosting step shouldn’t need to ask for it again.
What gets read automatically
On push, Railyard parses composer.json and .env.example and wires up what Laravel already declares about itself:
DB_CONNECTION=pgsqlormysqlin.env.exampledecides which database engine actually gets provisioned — not a dropdown to pick manually.php artisan migrate --forceruns as the release step before each deploy.APP_KEYis generated once, in Laravel’s ownbase64:format, and stored encrypted — never left for you to runphp artisan key:generateand paste somewhere.QUEUE_CONNECTION,CACHE_STORE,SESSION_DRIVERorBROADCAST_CONNECTIONset toredis(orlaravel/horizonpresent at all) provisions Redis and injects its connection variables with no addon to add by hand.
railyard create my-app https://github.com/me/my-app --addons mysql,redis
or the same thing from the dashboard once GitHub’s connected — every push after the first rebuilds and redeploys.
Queue workers are a process type, not a cron hack
laravel/horizon installed means the queue process runs php artisan horizon instead of the plain queue:work — detected from composer.json, not configured by hand. laravel/reverb installed adds a reverb process running php artisan reverb:start the same way. Each of these is the same build as web, just started with a different artisan command, scaled independently:
web: php artisan octane:start --server=frankenphp --host=0.0.0.0 --port=$PORT
queue: php artisan horizon
reverb: php artisan reverb:start
railyard scale my-app queue=2
A scheduler process is offered too, once routes/console.php or bootstrap/app.php schedules anything — running php artisan schedule:work continuously, or you can point Railyard’s own Cron at schedule:run on an interval instead; either is correct since schedule:run only fires what’s actually due.
Octane, if the app already uses it
laravel/octane in composer.json with no Dockerfile in the repo means the web process runs under FrankenPHP automatically (php artisan octane:start --server=frankenphp) instead of the traditional PHP-FPM request cycle — detected, not something to wire up in a Procfile by hand.
Config stays config, not a rebuild
Everything Laravel reads with env() lives under Variables, or railyard env:set my-app KEY=VALUE from the CLI — never baked into the image. The same build runs unchanged from a preview branch through production, which is the actual point of dev/prod parity: a staging bug is either real or it isn’t, never an artifact of staging running a different bundle than prod does.
Full reference: Laravel docs, Workers and scheduled jobs.