How to Install, Run, and Configure Magento 2 Cron Jobs
[Updated: March 18, 2026]
A single misconfigured cron job can stall your entire Magento store. Indexes stop updating, emails never send, and customers see stale prices.
This guide covers everything from initial cron setup to custom job creation, real troubleshooting commands, and performance tuning for production servers.
Key Takeaways
- Magento 2 uses three cron groups (index, default, consumers) to organize scheduled tasks across your store.
- Version 2.4.8 introduced automatic cron_schedule table cleanup and changed all new indexers to "Update by Schedule" mode.
- Custom cron jobs require a crontab.xml file in your module and an executable PHP class with an
execute()method. - The
bin/magento cron:runcommand must run twice: once to discover tasks and again to execute them. - Cron frequency, schedule lifetime, and history cleanup settings control both task timing and database table size on your server.
What Are Magento 2 Cron Jobs?
Magento 2 cron jobs = scheduled tasks that run at set intervals to keep your store operational. They handle indexing, email delivery, currency updates, and dozens of background processes.
Perfect for: store owners running production Magento instances, developers building custom modules, DevOps teams managing server infrastructure
Not ideal for: static sites without dynamic pricing, stores on fully managed PaaS that abstracts cron away
Magento 2 relies on the Unix cron daemon to trigger bin/magento cron:run at regular intervals. Each execution checks the cron_schedule database table for pending jobs and processes them in order.
Without cron running, your store breaks in predictable ways. Product prices stop updating. Transactional emails queue up but never send. Search indexes fall behind, and customers see outdated results.
Cron Groups in Magento 2
Magento organizes cron jobs into three groups. Each group runs on its own schedule and can be configured with separate settings.
| Group | Purpose | Examples |
|---|---|---|
| index | Reindexing operations | Catalog, price, search index updates |
| default | General maintenance tasks | Email sending, currency rates, sitemap generation, log cleaning |
| consumers | Message queue processing | Async operations, bulk API, inventory updates |
You can run a specific group in isolation:
bin/magento cron:run --group=index
This separation matters for performance. Index rebuilds are resource heavy. Running them in a dedicated group prevents slow indexing from blocking email delivery or other lightweight tasks.
How to Install Magento 2 Cron Jobs
Step 1: Connect to Your Server
Log into your Magento server via SSH as the filesystem owner. All Magento CLI commands must run under this user account.
ssh magento-user@your-server.com
Step 2: Navigate to the Magento Root Directory
cd /var/www/html/magento2
Replace the path with your actual Magento installation directory.
Step 3: Install the Cron Tab Entry
bin/magento cron:install
This adds a crontab entry for the current user. Use --force to overwrite an existing entry:
bin/magento cron:install --force
Step 4: Verify the Installation
crontab -l
You should see an entry like:
* * * * * /usr/bin/php /var/www/html/magento2/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento2/var/log/magento.cron.log
This runs every minute by default. Magento handles internal scheduling through the cron_schedule table, so the one minute interval is intentional.
Step 5: Remove the Cron Tab (When Needed)
bin/magento cron:remove
This removes the Magento crontab entry without affecting other cron jobs on the server.
How to Run Cron Jobs Manually
Run the cron command twice. The first execution discovers pending tasks. The second execution processes them.
bin/magento cron:run
bin/magento cron:run
Check execution results in the log file:
tail -50 var/log/cron.log
Manual execution is useful for testing custom cron jobs or debugging scheduling issues. In production, always rely on the automated crontab entry.
How to Configure Cron Settings
Admin Panel Configuration
Navigate to Stores > Configuration > Advanced > System > Cron (Scheduled Tasks).
Each cron group exposes these settings:
| Setting | Default | Purpose |
|---|---|---|
| Generate Schedules Every | 1 minute | How often cron creates new schedule entries |
| Schedule Ahead for | 4 minutes | How far in advance to schedule jobs |
| Missed if Not Run Within | 2 minutes | When a job gets "missed" status |
| History Cleanup Every | 10 minutes | How often old schedule entries are purged |
| Success History Lifetime | 60 minutes | How long successful job records persist |
| Failure History Lifetime | 600 minutes | How long failed job records persist |
Command Line Configuration
For more control, edit the crontab entry to adjust execution frequency:
*/5 * * * * /usr/bin/php /var/www/html/magento2/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento2/var/log/magento.cron.log
This example runs every 5 minutes instead of every minute. The five fields in cron syntax represent:
┌───────── minute (0-59)
│ ┌─────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌─── month (1-12)
│ │ │ │ ┌─ day of week (0-7, 0 and 7 = Sunday)
* * * * *
Creating Custom Cron Jobs
Custom cron jobs require two components: a PHP class with the business logic and a crontab.xml file that registers the schedule.
Step 1: Create the Executable Class
Place your class in your module's Cron directory:
<?php
namespace Vendor\Module\Cron;
use Psr\Log\LoggerInterface;
class CustomTask
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function execute(): void
{
$this->logger->info('Custom cron job executed');
// Your business logic here
}
}
Step 2: Register the Job in crontab.xml
Create etc/crontab.xml in your module:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="vendor_module_custom_task"
instance="Vendor\Module\Cron\CustomTask"
method="execute">
<schedule>0 */6 * * *</schedule>
</job>
</group>
</config>
This example runs every 6 hours. Change the group id to index or consumers based on the task type.
Step 3: Compile and Clear Cache
bin/magento setup:di:compile
bin/magento cache:clean
Step 4: Verify the Job
Run cron twice, then check the cron_schedule table:
SELECT * FROM cron_schedule
WHERE job_code = 'vendor_module_custom_task'
ORDER BY created_at DESC LIMIT 5;
Custom Cron Groups
For jobs that need isolated scheduling, create etc/cron_groups.xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/cron_groups.xsd">
<group id="custom_group">
<schedule_generate_every>1</schedule_generate_every>
<schedule_ahead_for>4</schedule_ahead_for>
<schedule_lifetime>2</schedule_lifetime>
<history_cleanup_every>10</history_cleanup_every>
<history_success_lifetime>60</history_success_lifetime>
<history_failure_lifetime>600</history_failure_lifetime>
<use_separate_process>1</use_separate_process>
</group>
</config>
Setting use_separate_process to 1 runs this group in its own PHP process, preventing resource heavy custom jobs from blocking core Magento tasks.
Cron Job Monitoring and Logging
Magento writes cron activity across four log files:
| Log File | Content |
|---|---|
var/log/cron.log |
Primary cron execution log. Check here first. |
var/log/exception.log |
Jobs that threw exceptions (error status) |
var/log/support_report.log |
Detailed failure reports for crashed jobs |
var/log/debug.log |
Missed job notifications (developer mode only) |
The cron_schedule database table stores the complete execution history:
SELECT job_code, status, created_at, scheduled_at, executed_at, finished_at
FROM cron_schedule
ORDER BY scheduled_at DESC LIMIT 20;
Status values in the table: pending, running, success, missed, error.
For production stores, consider adding server monitoring tools that alert on cron failures before they cascade into visible store issues.
Troubleshooting Magento 2 Cron Jobs
Cron Jobs Not Running
Check if the crontab entry exists:
crontab -l | grep magento
If empty, reinstall with bin/magento cron:install --force.
Verify PHP path:
which php
The path in your crontab must match your server's PHP binary. Mismatched paths (for example, /usr/bin/php vs /usr/local/bin/php) are a common cause of silent failures.
Jobs Stuck in "running" Status
Jobs can get stuck when PHP processes crash mid execution. Find and clear them:
SELECT * FROM cron_schedule WHERE status = 'running';
Reset stuck jobs:
UPDATE cron_schedule SET status = 'error'
WHERE status = 'running'
AND executed_at < DATE_SUB(NOW(), INTERVAL 1 HOUR);
cron_schedule Table Bloat
On busy stores, the cron_schedule table can grow to millions of rows and slow down cron execution itself.
Check table size:
SELECT COUNT(*) FROM cron_schedule;
Manual cleanup:
DELETE FROM cron_schedule
WHERE scheduled_at < DATE_SUB(NOW(), INTERVAL 7 DAY);
Magento 2.4.8 addresses this with automatic cleanup of entries for jobs that no longer exist in the system. For older versions, schedule a manual cleanup or reduce history_success_lifetime in the admin configuration.
Jobs in "missed" Status
A "missed" status means the job was scheduled but not executed within the Missed if Not Run Within window. Common causes:
- Cron daemon not running or stopped
- Previous cron execution took too long, delaying the schedule
- Server resource exhaustion (CPU or memory)
Check your Magento CLI output for memory or timeout errors when running cron.
Performance Optimization for Cron Jobs
Cron job configuration has a direct impact on server resource usage. Every minute, cron:run loads the Magento framework, checks the schedule table, and executes pending jobs.
Frequency Tuning
The default one minute interval suits most stores. For smaller stores with fewer scheduled tasks, running every 5 minutes reduces server load without noticeable impact.
For high traffic stores, keep the one minute interval but separate resource heavy jobs into custom cron groups with use_separate_process enabled.
Multi Node Considerations
On clustered Magento hosting setups, run the crontab on ONE node only. Running cron across multiple nodes causes duplicate job execution and database lock contention.
Index Mode Impact
Magento 2.4.8 defaults all new indexers to "Update by Schedule" mode instead of "Update on Save." This includes the Customer Grid indexer, which before 2.4.8 only supported "Update on Save." This shift moves reindexing work from real time (during admin saves) to cron execution. Monitor your index cron group to make sure reindex jobs complete within their scheduled window.
Database Optimization
The cron_schedule table benefits from periodic optimization. Run OPTIMIZE TABLE cron_schedule during low traffic periods to reclaim space after large deletes.
Keep history_success_lifetime and history_failure_lifetime as low as practical. For most stores, 60 minutes for successes and 600 minutes for failures provides enough diagnostic data without table bloat.
Securing Magento 2 Cron Jobs
File System Permissions
Restrict cron file execution to the Magento filesystem owner. No other user should be able to modify or execute cron related files.
chmod 750 bin/magento
chown magento-user:magento-group bin/magento
HTTP Access Protection
The legacy cron.php file was removed in Magento 2.4.0. All cron execution now happens through the CLI. If you upgraded from an older version, verify that cron.php is not accessible via HTTP.
Block access in your Nginx configuration:
location ~ ^/(cron|setup|dev) {
deny all;
return 403;
}
Environment Variables
Store sensitive configuration (database credentials, API keys) in env.php or server environment variables. Never hardcode credentials in cron job classes.
Audit Trail
Review cron_schedule entries for unexpected job codes. Third party extensions can register cron jobs that run with full Magento framework access. Audit installed extensions and remove unused ones to minimize the cron attack surface.
What Changed in Magento 2.4.8
Magento 2.4.8 (released April 8, 2025, supported until April 2028) introduced four cron related improvements (full release notes):
-
Automatic cron_schedule cleanup. The system now removes schedule entries for jobs that no longer exist in the codebase. This prevents orphaned entries from accumulating after extension removal.
-
Indexers default to "Update by Schedule." All new indexers use schedule mode instead of "Update on Save." This reduces real time processing during admin operations but increases cron workload.
-
Customer Grid indexer supports both modes. Before 2.4.8, the Customer Grid indexer only supported "Update on Save." It now supports both modes and defaults to "Update by Schedule." After upgrading, verify your indexer mode:
bin/magento indexer:show-mode customer_grid. -
Changelog table management. The system removes unused changelog tables when switching indexer modes, keeping the database clean.
These changes require PHP 8.3 or PHP 8.4. PHP 8.1 support was removed in 2.4.8, and PHP 8.2 is supported for upgrades only.
Next Steps
Proper cron configuration keeps your Magento store running without manual intervention. Start with the default settings, monitor your cron.log for errors, and adjust scheduling as your store grows.
For stores that need zero cron management overhead, managed Magento hosting handles cron setup, monitoring, and optimization as part of the infrastructure.
FAQ
What happens if Magento cron stops running?
Indexes fall behind, transactional emails stop sending, currency rates freeze, and the cron_schedule table fills with pending jobs. Product prices and catalog search results become stale.
How often should Magento cron run?
Every minute is the recommended default. Magento manages internal job scheduling through the cron_schedule table. The one minute crontab interval ensures jobs execute close to their scheduled time.
Can I run cron on multiple servers in a cluster?
Run the crontab on one node only. Multiple nodes executing cron causes duplicate job processing and database lock conflicts. Use a dedicated cron node or a process manager to enforce single execution.
How do I check if a specific cron job ran?
Query the cron_schedule table: SELECT * FROM cron_schedule WHERE job_code = 'your_job_code' ORDER BY scheduled_at DESC LIMIT 10;. Check the status column for success, error, or missed.
What is the difference between cron groups?
Groups isolate jobs with different scheduling needs. The index group handles reindexing, default covers general tasks like emails and cleanup, and consumers process message queue operations. Each group can have independent timing and lifetime settings.
How do I create a custom cron job in Magento 2?
Create a PHP class with an execute() method, then register it in your module's etc/crontab.xml file with a schedule expression. Run bin/magento setup:di:compile and clear cache to activate.
Why are my cron jobs showing "missed" status?
The job was scheduled but not executed within the configured window. Check that the cron daemon is running, previous jobs are not blocking execution, and the server has sufficient CPU and memory resources.
How do I clean up the cron_schedule table?
Reduce history_success_lifetime and history_failure_lifetime in admin settings. For immediate cleanup, run DELETE FROM cron_schedule WHERE scheduled_at < DATE_SUB(NOW(), INTERVAL 7 DAY);. Magento 2.4.8 auto cleans orphaned entries.
Does cron configuration affect store performance?
Yes. Each cron execution loads the full Magento framework. Resource heavy jobs (reindexing, bulk operations) running during peak traffic compete with web requests for CPU and memory. Schedule heavy jobs during low traffic windows.
What PHP version does cron require in Magento 2.4.8?
Magento 2.4.8 requires PHP 8.3 or PHP 8.4. The CLI PHP binary used in crontab must match the web server PHP version. Mismatched versions cause unexpected behavior.