Scheduled Tasks and Cron Jobs: Automating Laravel Workflows
Learn to master Laravel scheduling to automate recurring tasks like reporting and cleanup. Replace complex crontabs with clean, version-controlled PHP code.
Previously in this course, we explored Command Line Tools with Artisan: Automating Laravel Workflows. Now that you can build custom CLI commands, the next logical step is automating their execution. Instead of managing dozens of individual server-level cron jobs, Laravel allows you to define your entire schedule within your application code.
The Problem with Traditional Cron
In a standard Linux environment, you would edit your crontab file to run commands. This approach is brittle: your schedule lives outside your repository, it's hard to version control, and it's a nightmare to manage across staging and production environments.
Laravel’s scheduling system acts as a wrapper around the system cron. You only need to add a single entry to your server's crontab, and Laravel handles the rest.
Defining Scheduled Tasks
In modern Laravel versions, the schedule is defined in routes/console.php. You use the Schedule facade to define tasks that should run at specific intervals.
Let’s advance our project board application. We want to automatically delete tasks that have been marked as "archived" for more than 30 days.
First, ensure you have an Artisan command (as learned in our previous lesson) called app:prune-old-tasks. Now, register it in routes/console.php:
PHPuse Illuminate\Support\Facades\Schedule; Schedule::command('app:prune-old-tasks')->daily();
The daily() method is a helper for a standard cron expression. You can also use everyMinute(), weekly(), or monthly().
Advanced Scheduling with Cron Expressions
When built-in helpers aren't enough, you can use the cron() method to pass raw cron expressions. This gives you full control over the timing.
For example, if you need to run a report every Monday at 3:00 AM:
PHPSchedule::command('app:generate-weekly-report') ->cron('0 3 * * 1');
You can also chain methods to control execution constraints:
PHPSchedule::command('app:prune-old-tasks') ->dailyAt('02:00') ->environments(['production']) ->withoutOverlapping();
environments(['production']): Prevents the task from running in local or staging environments.withoutOverlapping(): Ensures that if the previous execution is still running, the new one won't start. This is critical for long-running cleanup jobs.
Handling Task Output
When tasks run in the background, you won't see their output in your terminal. To debug or keep a record, you should direct the output to a log file or send it via email.
PHPSchedule::command('app:prune-old-tasks') ->daily() ->appendOutputTo(storage_path('logs/scheduler.log')) ->emailOutputOnFailure('admin@example.com');
Using appendOutputTo is essential for production monitoring. If a task fails silently, you need that log file to diagnose the issue.
Hands-on Exercise
- Open your project's
routes/console.phpfile. - Register a new task that runs
app:generate-weekly-reportevery Sunday at midnight. - Add
withoutOverlapping()to ensure it doesn't collide with other processes. - Append the output to
storage/logs/reports.log. - Verify your schedule by running
php artisan schedule:listin your terminal.
Common Pitfalls
- Forgetting the single Cron entry: You must add
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1to your server’s crontab. Without this, your defined schedule will never trigger. - Overlapping Tasks: If a task takes longer than the interval (e.g., a report that takes 2 minutes to generate but is scheduled
everyMinute), you will end up with multiple processes competing for database locks. Always usewithoutOverlapping(). - Environment Leaks: Running cleanup commands in your local environment can be destructive. Always use
->environments(['production'])for sensitive tasks.
Recap
Scheduling in Laravel turns complex server management into readable, version-controlled code. By using the Schedule facade, we can define our task intervals, handle overlaps, and ensure our application maintains its health through automated cleanup and reporting. This is a core component of building robust, autonomous systems.
Up next: We will dive into Job Chaining and Batching, where we'll learn how to handle complex, multi-step background processes that depend on each other.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

AI Automation & Agentic Workflow Development
Automate the repetitive work eating your time — content pipelines, data workflows, and agentic AI tasks that run themselves.