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
* * * * * cd /path/to/artisan && php artisan schedule:run >> /dev/null 2>&1Schedule::command('emails:send')->dailyAt('09:00');
Schedule::call(fn () => Cache::flush())->hourly();
Schedule::command('report:weekly')->weeklyOn(1, '08:00');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.
Related Tools
Platform Guides
Cron syntax for Linux, Kubernetes, AWS, and more
Spring @Scheduled Cron Guide
How Spring's @Scheduled annotation uses cron expressions: 6-field Quartz-inspired syntax, fixedRate vs cron, and common configuration patterns.
Cron in Docker Guide
Docker has no built-in cron. See the common patterns for scheduled jobs in containers: cron inside the container, sidecar containers, and orchestrator-native scheduling.