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.