Laravel scheduler transforms one cron entry into a rich timetable of commands, closures, and queued jobs with overlap protection, environments, and maintenance mode awareness.
Defining Scheduled Tasks
Schedule definitions live in routes/console.php in Laravel 11 or app/Console/Kernel.php in older versions.
The Schedule facade accepts commands, invokable classes, jobs, and shell callbacks.
Step 1: Register a basic command schedule
Add Schedule::command('reports:daily')->dailyAt('08:00'); in routes/console.php.
List schedules with php artisan schedule:list showing next run times and cron expressions.
Schedule::command('reports:daily')->dailyAt('08:00');
Step 2: Create the Artisan command
Run php artisan make:command SendDailyReport and implement handle() with business logic or dispatch a job.
Keep commands thin—delegate heavy work to queued jobs for retry support.
php artisan make:command SendDailyReport
Step 3: Schedule closures and invokable classes
Schedule::call(fn () => CleanupService::run())->hourly() works for small tasks.
Invokable classes improve testability: Schedule::call(new PruneTempFiles)->daily().
Schedule::call(new PruneTempFiles)->daily();
Step 4: Queue scheduled tasks
Chain ->job(new GenerateReport)->daily() to push work to the queue instead of running inline.
Queued schedules need workers running. Inline schedules need the scheduler process itself.
Schedule::job(new GenerateReport)->dailyAt('06:00');
Cron Expressions and Constraints
Laravel fluent methods like hourly(), weeklyOn(), and cron() map to cron syntax.
Constraints prevent tasks from running during deployments or outside business hours.
Step 1: Use fluent scheduling methods
Examples: ->everyMinute(), ->twiceDaily(1, 13), ->weekdays(), ->monthlyOn(1, '00:00').
Prefer fluent methods over raw cron strings for readability unless you need exotic timing.
Schedule::command('sync:inventory')->everyFiveMinutes()->between('8:00', '20:00');
Step 2: Prevent overlapping runs
Chain ->withoutOverlapping() so a slow run does not stack duplicates. Optional ->runInBackground() for shell commands.
Mutex uses cache by default. Ensure cache driver supports atomic locks in production.
Schedule::command('imports:run')->hourly()->withoutOverlapping();
Step 3: Limit to environments
Use ->environments(['production']) so staging does not send live emails or charge customers.
Combine with ->when(fn () => config('features.reports')) for feature-flagged schedules.
Schedule::command('billing:charge')->daily()->environments(['production']);
Step 4: Maintenance mode behavior
Tasks skip automatically during php artisan down unless ->evenInMaintenanceMode() is set.
Critical health checks may use evenInMaintenanceMode while batch emails should pause.
Schedule::command('health:ping')->everyMinute()->evenInMaintenanceMode();
Server Cron and Monitoring
Production servers need exactly one cron entry calling schedule:run every minute.
Log output and alert on failures to catch silent scheduler breakage.
Step 1: Add crontab entry
Run crontab -e and add * * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1.
Use absolute paths and the deploy user. Wrong paths are the most common scheduler failure.
* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1
Step 2: Test with schedule:run locally
php artisan schedule:run executes due tasks immediately. Use schedule:test for interactive debugging in Laravel 11.
Temporarily set ->everyMinute() during development to verify wiring.
php artisan schedule:run
php artisan schedule:test
Step 3: Log output to files
Chain ->sendOutputTo(storage_path('logs/backup.log')) or appendOutputTo for audit trails.
Email output sparingly with emailOutputTo—prefer centralized logging.
->appendOutputTo(storage_path('logs/daily-report.log'));
Step 4: Monitor with Laravel Pulse or external tools
Track scheduler heartbeat externally. If schedule:run stops, alerts fire before missed backups become incidents.
Document every scheduled task in your ops runbook with owner and expected duration.
- Heartbeat monitoring
- Runbook per scheduled task
Aadyanex builds production-ready Laravel applications with clean architecture, secure APIs, and long-term support.
