Home › Cron Jobs with Laravel
Cron Jobs in Laravel
Laravel Task Scheduling replaces individual crontab entries with a single entry that drives all your scheduled jobs from PHP code.
The One Crontab Entry
Laravel's entire scheduling system runs from a single cron entry. Add this to your server's crontab and never touch it again. Official reference: Laravel Task Scheduling documentation.
* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1
This runs every minute. Laravel decides internally which jobs are due. All your schedule definitions live in PHP code, version-controlled with your project.
The cd part matters
The cd /var/www/html && sets the working directory before running Artisan.
Without it, Artisan cannot find your .env file or bootstrap Laravel correctly.
Replace /var/www/html with the actual path to your Laravel project root.
Defining Schedules (Laravel 9+)
In Laravel 9 and above, schedules go in routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')->daily();
Schedule::command('reports:generate')->weeklyOn(1, '8:00');
Schedule::command('cache:clear')->hourly();
Schedule::call(function () {
DB::table('temp_data')->where('created_at', '<', now()->subDays(7))->delete();
})->daily()->at('03:00');
Frequency Methods
| Method | Description | Equivalent cron |
|---|---|---|
->everyMinute() | Every minute | * * * * * |
->everyFiveMinutes() | Every 5 minutes | */5 * * * * |
->hourly() | Every hour | 0 * * * * |
->daily() | Every day at midnight | 0 0 * * * |
->dailyAt('13:00') | Every day at 1 PM | 0 13 * * * |
->weekly() | Every Sunday at midnight | 0 0 * * 0 |
->weeklyOn(1, '8:00') | Every Monday at 8 AM | 0 8 * * 1 |
->monthly() | First of every month | 0 0 1 * * |
->cron('30 9 * * 1-5') | Custom expression | Any expression |
Important Options
Prevent overlapping runs
By default, Laravel runs a job even if the previous one is still running. For long jobs, add withoutOverlapping():
Schedule::command('import:data')
->hourly()
->withoutOverlapping();
Run only on one server
If you have multiple app servers, each one runs the scheduler. Use onOneServer() to ensure only one fires the job (requires a cache driver that supports atomic locks):
Schedule::command('report:generate')
->daily()
->onOneServer();
Timezone
By default, schedules use the app timezone from config/app.php.
Override per job:
Schedule::command('emails:send')
->daily()
->timezone('Europe/Madrid');
Output to log
Send job output to a file or email:
Schedule::command('backup:run')
->daily()
->appendOutputTo('/var/log/backup.log');
Debugging Laravel Schedules
List all scheduled jobs
php artisan schedule:list
Shows every scheduled job, its expression and when it runs next.
Run the scheduler manually
php artisan schedule:run
Triggers any jobs due to run right now. Useful for testing without waiting for cron.
Run a specific job immediately
php artisan schedule:test
Interactive command that lets you pick a scheduled job and run it immediately, regardless of its schedule.
Keep the scheduler running locally
php artisan schedule:work
Runs the scheduler every minute in the foreground - useful for local development without a crontab.
Need a custom cron expression for ->cron()?
Use the generator to build your expression visually, then paste it directly into the ->cron('...') method.