Skip to main content

Laravel Horizon

What is Laravel Horizon?

Laravel Horizon is Laravel's official dashboard and configuration layer for Redis-backed queues, it doesn't replace the queue worker process, it supervises and reports on it. This container isn't a standalone daemon in the usual sense: it's a dedicated PHP/Alpine image (built via supervisord, extending Laradock's usual PHP extension-install pattern) whose job is to run php artisan horizon against your mounted Laravel application, under depends_on: workspace.

First-run setup (required)

The container ships with only an example supervisord program file, laravel-horizon/supervisord.d/laravel-horizon.conf.example. Supervisord only loads files matching *.conf, so on a fresh checkout it loads nothing and the container starts but never actually runs php artisan horizon. Copy the example once before your first start:

cp laravel-horizon/supervisord.d/laravel-horizon.conf.example laravel-horizon/supervisord.d/laravel-horizon.conf

*.conf is gitignored on purpose (laravel-horizon/supervisord.d/.gitignore) so your local copy is never committed. Do this before starting the container, or restart it afterward if you already started it without the file.

Start Laravel Horizon

Your app must already have Horizon installed (composer require laravel/horizon) and configured to use the redis queue connection. Then:

./laradock start laravel-horizon

The container depends_on workspace in compose.yml, so Compose starts it first automatically. It also needs redis running and reachable, since that's what php artisan horizon actually connects to.

Stop Laravel Horizon

Stopping just pauses the container; horizon simply stops processing until you start it again:

./laradock stop laravel-horizon

This stops the container, which stops the supervised horizon process along with it. To remove the container:

./laradock remove laravel-horizon

Configuration

Laravel Horizon's own dashboard and queue settings live in your Laravel app (config/horizon.php), not in this container. What this container's laravel-horizon/defaults.env controls is which optional PHP extensions get compiled into its image at build time, all false by default:

VariableDefaultWhat it does
LARAVEL_HORIZON_INSTALL_BZ2falseInstall the bz2 extension.
LARAVEL_HORIZON_INSTALL_GDfalseInstall the gd extension.
LARAVEL_HORIZON_INSTALL_GMPfalseInstall the gmp extension.
LARAVEL_HORIZON_INSTALL_GNUPGfalseInstall the gnupg extension.
LARAVEL_HORIZON_INSTALL_LDAPfalseInstall the ldap extension.
LARAVEL_HORIZON_INSTALL_IMAGEMAGICKfalseInstall imagick, version controlled by LARAVEL_HORIZON_IMAGEMAGICK_VERSION.
LARAVEL_HORIZON_INSTALL_INTLfalseInstall the intl extension.
LARAVEL_HORIZON_IMAGEMAGICK_VERSIONlatestGit ref of the imagick PECL/source build, used only when ImageMagick is installed.
LARAVEL_HORIZON_INSTALL_SOCKETSfalseInstall the sockets extension.
LARAVEL_HORIZON_INSTALL_YAMLfalseInstall the yaml extension.
LARAVEL_HORIZON_INSTALL_ZIP_ARCHIVEfalseInstall the zip extension.
LARAVEL_HORIZON_INSTALL_PHPREDISfalseInstall the redis PECL extension (in addition to predis, if your app uses it).
LARAVEL_HORIZON_INSTALL_MONGOfalseInstall the mongodb extension.
LARAVEL_HORIZON_INSTALL_CASSANDRAfalseInstall the Cassandra PHP driver.
LARAVEL_HORIZON_INSTALL_FFMPEGfalseInstall the ffmpeg binary for jobs that process media.
LARAVEL_HORIZON_INSTALL_AUDIOWAVEFORMfalseInstall the BBC audiowaveform binary.
LARAVEL_HORIZON_INSTALL_POPPLER_UTILSfalseInstall poppler-utils and antiword for PDF/document jobs.
LARAVEL_HORIZON_PUID1000UID for the container's laradock user.
LARAVEL_HORIZON_PGID1000GID for the container's laradock user.

This container also inherits PHP_FPM_INSTALL_PGSQL, PHP_FPM_INSTALL_BCMATH, and PHP_FPM_INSTALL_MEMCACHED from the shared PHP-FPM build args, so those extensions follow whatever you've already set for php-fpm.

Supervise queue workers

The actual worker process(es) Horizon supervises are configured on the Laravel side, in config/horizon.php (queues, balance strategy, max processes, and so on), same as any Horizon setup. This container just needs Redis and your app code reachable to run php artisan horizon:

./laradock start redis workspace laravel-horizon

Supervisord config for the container itself lives in laravel-horizon/supervisord.d (see First-run setup if you haven't created laravel-horizon.conf yet), mounted straight into /etc/supervisord.d, edit it if you need to change how the horizon process is launched or restarted inside the container. It's a volume mount, not baked into the image, so a restart picks up your edit, no rebuild needed:

./laradock restart laravel-horizon

Manage Horizon from the CLI

Open a terminal inside the container, the same way as any other Laradock service:

./laradock enter laravel-horizon

Then use Horizon's own Artisan commands, the same ones you'd use outside Docker:

CommandWhat it does
php artisan horizon:statusPrint whether Horizon is currently running or paused.
php artisan horizon:pausePause processing without stopping the container.
php artisan horizon:continueResume after a pause.
php artisan horizon:terminateGracefully stop after current jobs finish; supervisord (autorestart=true) restarts the process immediately, this is the standard way to pick up freshly deployed code without dropping in-flight jobs.
php artisan horizon:clearRemove all pending jobs from the queues Horizon is watching.

Common issues

  • Horizon container is running but nothing shows in the dashboard. You most likely skipped First-run setup: without laravel-horizon.conf, supervisord has no program to run, so php artisan horizon never starts even though the container itself is healthy.
  • Horizon container starts but no jobs process. Confirm your Laravel app's QUEUE_CONNECTION=redis and that redis is running and reachable; Horizon only supervises Redis-backed queues.
  • Missing PHP extension errors from your app's jobs. The extension flags above are all false by default; if a job needs gd, imagick, mongodb, and so on, set the matching LARAVEL_HORIZON_INSTALL_* variable and rebuild: ./laradock rebuild laravel-horizon.
  • Extension build args changed but the container still lacks them. These are Dockerfile build args, not runtime env vars; a plain restart won't apply them, rebuild the image after changing .env.
  • Horizon dashboard (/horizon) shows no metrics. That dashboard is served by your app itself (through php-fpm/nginx), not by this container; this container only needs to be running so the underlying queue actually gets worked.
  • Edited supervisord.d/laravel-horizon.conf but nothing changed. Supervisord only reads that file at process start; restart the container (./laradock restart laravel-horizon), don't just wait.

Need the queue backend itself? See Redis. New to Laradock? Start at Getting Started.