/
Application Framework

Laravel Task Scheduler Guide

Laravel's scheduler lets you define all of an application's recurring tasks in PHP code (routes/console.php or the Console\Kernel class, depending on Laravel version) using a fluent, readable API — instead of managing a dozen separate crontab entries, your server's actual crontab needs exactly one line pointing at Laravel's own scheduler.

Syntax Notes

Under the hood, Laravel's fluent methods (->daily(), ->hourly(), ->weeklyOn()) compile down to standard cron expressions, but you can also call ->cron('* * * * *') directly with a raw expression if the fluent API doesn't cover your exact case.

Examples

The one crontab entry Laravel needs
* * * * * cd /path/to/artisan && php artisan schedule:run >> /dev/null 2>&1
Defining scheduled tasks (fluent API)
Schedule::command('emails:send')->dailyAt('09:00');
Schedule::call(fn () => Cache::flush())->hourly();
Schedule::command('report:weekly')->weeklyOn(1, '08:00');
Raw cron expression when the fluent API isn't enough
Schedule::command('inventory:sync')->cron('*/15 9-17 * * 1-5');

Gotchas

  • Laravel's scheduler only actually checks and runs due tasks when `schedule:run` is invoked — this requires exactly one crontab entry running every minute; forgetting that single entry means none of the fluent schedule definitions in your code will ever fire.
  • By default, overlapping runs are allowed if a task takes longer than its interval — use `->withoutOverlapping()` explicitly for any task that shouldn't have two instances running concurrently.
  • Scheduled tasks run in the timezone configured in config/app.php ('timezone') by default, not necessarily the server's OS timezone — mismatches between the two are a common source of "my task ran at the wrong time" confusion.

Best Practices

  • Add `->withoutOverlapping()` to any task where a slow run could overlap the next scheduled invocation, and `->onOneServer()` if you're running the scheduler on multiple load-balanced servers.
  • Use `->emailOutputOnFailure()` or send failures to your logging/monitoring stack — Laravel's scheduler runs silently by default, so failures can go unnoticed without explicit output handling.
  • Run `php artisan schedule:list` to see every registered scheduled task and its next run time — invaluable for verifying what's actually configured versus what you assume is configured.

Frequently Asked Questions

Do I need a crontab entry for every scheduled task in Laravel?
No — exactly one crontab entry (running php artisan schedule:run every minute) is needed regardless of how many tasks you define in code. Laravel's scheduler checks all defined tasks internally and runs whichever are due.
Can I use raw cron syntax instead of the fluent methods?
Yes — every scheduled task supports ->cron('* * * * *') with a standard cron expression directly, for cases the fluent API (->daily(), ->hourly(), etc.) doesn't conveniently express.
How do I test a scheduled task without waiting for its actual time?
Run `php artisan schedule:run` manually (it executes any task that's currently due), or call the underlying Artisan command/closure directly to test its logic independent of scheduling.