← Blog

Deploying Laravel without hand-writing a queue worker config

Railyard

October 12, 2026

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=pgsql or mysql in .env.example decides which database engine actually gets provisioned — not a dropdown to pick manually.
  • php artisan migrate --force runs as the release step before each deploy.
  • APP_KEY is generated once, in Laravel’s own base64: format, and stored encrypted — never left for you to run php artisan key:generate and paste somewhere.
  • QUEUE_CONNECTION, CACHE_STORE, SESSION_DRIVER or BROADCAST_CONNECTION set to redis (or laravel/horizon present 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.

Push a Laravel app right now.

composer.json and .env.example are read automatically — migrations, queue worker and database all wired up.

Free plan, no card, and 14 days of Pro for every new team. One flat price per team.