Running Laravel Queues on cPanel with Cron Jobs
Laravel queues are useful for work that should not block an HTTP request, such as sending email, generating reports, importing data, or processing files. On a VPS, a process supervisor is usually the best way to keep long-running queue workers alive. Shared cPanel hosting often does not provide that option, so a cron-driven worker can be a practical fallback.
This pattern starts a worker periodically and tells it to exit once the queue becomes empty.
1. Schedule the Queue Worker
In current Laravel applications, scheduled tasks are commonly defined in routes/console.php with the Schedule facade:
use Illuminate\Support\Facades\Schedule;
Schedule::command('queue:work --stop-when-empty')
->everyMinute()
->withoutOverlapping();Older Laravel applications may define the same schedule in app/Console/Kernel.php.
The options mean:
queue:workstarts a queue worker.--stop-when-emptyexits after the currently available jobs have been processed.everyMinute()lets the Laravel scheduler consider the command every minute.withoutOverlapping()prevents the scheduler from starting a second copy while the previous scheduled invocation is still considered active.
For long-running jobs, configure suitable worker timeouts, retry policies, and the withoutOverlapping() lock expiration so a crashed process does not leave an unexpectedly long-lived lock.
2. Add a cPanel Cron Job
Open cPanel → Cron Jobs and add a cron entry that runs Laravel’s scheduler once per minute. The PHP executable depends on the hosting provider and selected PHP version.
For example:
* * * * * /usr/local/bin/ea-php84 /home/{account_name}/live/artisan schedule:runAnother server may expose a different binary such as ea-php83, php, or a versioned path. Confirm the exact PHP CLI path in your hosting environment.
Replace:
{account_name}with the cPanel account name.livewith the Laravel project directory.ea-php84with the PHP CLI binary used by the application.
It is also a good idea to change into the project directory explicitly when the hosting environment requires it:
* * * * * cd /home/{account_name}/live && /usr/local/bin/ea-php84 artisan schedule:run >> /dev/null 2>&1Only discard output after you have a separate logging and monitoring strategy; during setup, keeping cron errors visible is useful.
3. How the Flow Works
- Cron runs
php artisan schedule:runevery minute. - Laravel evaluates the application schedule.
- When due, the scheduler launches
queue:work --stop-when-empty. - The worker processes available jobs and exits after the queue is empty.
- A later cron invocation starts another worker when needed.
This is not equivalent to a continuously running worker—new jobs may wait until the next cron cycle—but it can be sufficient for shared-hosting workloads that tolerate that delay.
4. Practical Tips
A database-backed queue is often available on shared hosting:
QUEUE_CONNECTION=databaseCreate the required queue table using the commands appropriate for your Laravel version, then migrate the database. In versions that provide the command, that may look like:
php artisan make:queue-table
php artisan migrateOther useful operational commands include:
php artisan queue:failed
php artisan queue:retry {id}Also consider:
- Keeping queued jobs small and idempotent so retries are safe.
- Configuring failed-job storage and monitoring it.
- Setting
--tries,--timeout, and queue names when the defaults do not fit your workload. - Using separate cron entries for separate Laravel projects.
- Moving to a persistent process manager, container platform, or managed queue worker when job volume or latency requirements grow.
Conclusion
On cPanel hosting without a process supervisor, running schedule:run every minute and scheduling queue:work --stop-when-empty can keep Laravel queues moving with minimal infrastructure. It is a useful shared-hosting compromise, but a continuously supervised worker remains the better option when low latency, throughput, and worker observability matter.