Traditionally, you would create a cron entry on your server for every recurring task. This approach scatters your schedule definitions outside version control and requires SSH access every time you want to change them.Laravel’s scheduler lets you define all scheduled tasks in code, using an expressive API. You only need one cron entry on your server, and your entire schedule lives alongside your application.Define your scheduled tasks in routes/console.php:
use App\Console\Commands\SendEmailsCommand;use Illuminate\Support\Facades\Schedule;// Schedule by command nameSchedule::command('emails:send Taylor --force')->daily();// Schedule by class name with an array of argumentsSchedule::command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();
You can also chain a schedule method directly onto a closure command:
Artisan::command('delete:recent-users', function () { DB::table('recent_users')->delete();})->purpose('Delete recent users')->daily();
use App\Jobs\Heartbeat;use Illuminate\Support\Facades\Schedule;Schedule::job(new Heartbeat)->everyFiveMinutes();// Specify the queue and connectionSchedule::job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();
use Illuminate\Support\Facades\Schedule;// Every Monday at 13:00Schedule::call(function () { // ...})->weekly()->mondays()->at('13:00');// Weekdays, hourly, between 08:00 and 17:00Schedule::command('foo') ->weekdays() ->hourly() ->between('8:00', '17:00');
use Illuminate\Support\Facades\Schedule;Schedule::command('report:generate') ->timezone('America/Chicago') ->at('9:00');
Set a default timezone for all tasks in config/app.php:
'schedule_timezone' => 'America/Chicago',
If a timezone observes daylight saving time, a task scheduled during the transition hour may run twice (when clocks fall back) or be skipped entirely (when clocks spring forward). UTC avoids these issues and is the safest choice for scheduled tasks.
By default, a task starts even if the previous run is still executing. Use withoutOverlapping() to ensure only one instance runs at a time:
use Illuminate\Support\Facades\Schedule;Schedule::command('emails:send')->withoutOverlapping();// Expire the lock after 10 minutes instead of the default 24 hoursSchedule::command('emails:send')->withoutOverlapping(10);
withoutOverlapping() uses the application cache to manage locks. If a task gets stuck, clear the lock with php artisan schedule:clear-cache.
use Illuminate\Support\Facades\Schedule;// Run only when the closure returns trueSchedule::command('emails:send')->daily()->when(fn () => true);// Skip when the closure returns trueSchedule::command('emails:send')->daily()->skip(fn () => true);// Run only in specific environmentsSchedule::command('emails:send') ->daily() ->environments(['staging', 'production']);// Run only between 07:00 and 22:00Schedule::command('emails:send') ->hourly() ->between('7:00', '22:00');
use Illuminate\Support\Facades\Schedule;// Write output to a fileSchedule::command('emails:send') ->daily() ->sendOutputTo(storage_path('logs/emails-send.log'));// Append output to an existing fileSchedule::command('emails:send') ->daily() ->appendOutputTo(storage_path('logs/emails-send.log'));// Email output on completionSchedule::command('report:generate') ->daily() ->sendOutputTo($filePath) ->emailOutputTo('[email protected]');// Email output only on failureSchedule::command('report:generate') ->daily() ->emailOutputOnFailure('[email protected]');
Normal cron only goes down to one-minute intervals. Laravel supports per-second scheduling:
use Illuminate\Support\Facades\Schedule;Schedule::call(function () { DB::table('recent_users')->delete();})->everySecond();
When sub-minute tasks are defined, schedule:run stays alive for the entire minute and fires them at the right moments.To interrupt an in-progress schedule:run during a deployment:
php artisan schedule:list # List all tasks and next run timesphp artisan schedule:run # Run due tasks (called by cron every minute)php artisan schedule:work # Run the scheduler continuously (local development)php artisan schedule:pause # Pause all scheduled tasksphp artisan schedule:continue # Resume scheduled tasksphp artisan schedule:clear-cache # Clear overlap-prevention locksphp artisan schedule:interrupt # Interrupt the running schedule:run process
Artisan console
Build custom Artisan commands to use in your scheduled tasks.