Laravel's scheduler is a single entry point that reads your defined schedule and decides what actually needs to run — the server-level cron job itself never changes, no matter how many scheduled tasks you add or remove.
1. The one crontab entry
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
This has to run every minute — not because every task fires every minute, but because schedule:run is what checks, each minute, whether anything on the actual schedule is due right now.
2. Defining the schedule — Laravel 11+
In newer Laravel, scheduled tasks are defined in routes/console.php (or via withSchedule() in bootstrap/app.php), not in a Kernel class:
use Illuminate\Support\Facades\Schedule;
Schedule::command('invites:prune')->daily();
Schedule::call(fn () => Cache::flush())->weekly();
Laravel 10 and earlier
Defined inside app/Console/Kernel.php's schedule(Schedule $schedule) method instead — same fluent API, different location. If you're following an older tutorial and can't find Kernel.php in a fresh install, that's the Laravel 11 restructure, not a missing file.
Testing without waiting for cron
php artisan schedule:run # runs whatever is due right now
php artisan schedule:list # shows every scheduled task and its next run time
Overlapping runs
A long-running task can still be executing when the next minute's schedule:run fires. Use ->withoutOverlapping() on tasks that shouldn't run concurrently with themselves — without it, a slow task can end up with multiple copies running at once.