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:work starts a queue worker.
  • --stop-when-empty exits 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:run

Another 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.
  • live with the Laravel project directory.
  • ea-php84 with 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>&1

Only discard output after you have a separate logging and monitoring strategy; during setup, keeping cron errors visible is useful.

3. How the Flow Works

  1. Cron runs php artisan schedule:run every minute.
  2. Laravel evaluates the application schedule.
  3. When due, the scheduler launches queue:work --stop-when-empty.
  4. The worker processes available jobs and exits after the queue is empty.
  5. 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=database

Create 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 migrate

Other 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.