Scheduled Tasks in Joomla

This content was generated with the assistance of AI and should be verified against the official Joomla documentation before being relied on in production.

This sub-section’s Joomla bibliography lists the reference material consulted while preparing these pages.

Scheduled Tasks is Joomla’s built-in replacement for hand-made cron jobs. It is the component com_scheduler, added in Joomla 4.1, and it lets an administrator run routine work (purging sessions, rotating logs, releasing checked-out articles, calling a URL) on a timetable from System → Scheduled Tasks. This page was checked on 2026-10-30 against Joomla 6.2 (PHP 8.3 or later), the Joomla User Guide at https://guide.joomla.org/ and the com_scheduler and plugins/task sources of the Joomla CMS repository. The running example is the Tallpine Hiking Club site (package pkg_tallpine), which needs nightly housekeeping and one custom task that syncs trail closures. How to write such a task is covered in Scheduled task plugins; this page is about using and operating the scheduler.

What the scheduler is and who uses it

A task is a row in the database that points at a routine offered by a task plugin, plus a timetable, a priority and a few parameters. The site builder creates tasks; the administrator decides what triggers the scheduler; the developer supplies new routines. Joomla ships with several task plugins and with some tasks already created, and third-party extensions can add routines of their own. The tasks run at most when something starts the scheduler, which is the central design point: Joomla has no daemon, so something has to ask it to look for due tasks. There are three ways to do that and the User Guide advises using only one of them at a time.

flowchart TD L[Lazy scheduler: visitor loads an HTML page] --> A[com_ajax request] W[Web cron: external cron calls a URL with a key] --> A2[com_ajax request, site client] C[System cron: php cli/joomla.php scheduler:run] --> S A --> S[Scheduler picks a due task] A2 --> S S --> K{Lock acquired?} K -- no --> X[Skip, try later] K -- yes --> R[Task plugin routine runs] R --> U[Exit code, counters and next run saved, lock released]

The three ways to start the scheduler

The choice is made in System → Scheduled Tasks → Options (the com_scheduler configuration). The fields in config.xml are lazy_scheduler.enabled (default on), lazy_scheduler.interval (default 300), webcron.enabled (default off), the generated webcron.key, the read-only webcron.base_link and a webcron.reset_key switch, plus a timeout value (default 300 seconds) and the permissions tab.

Lazy scheduler

The lazy scheduler needs no setup and is on by default. The system plugin System - Schedule Runner (plg_system_schedulerunner) listens to onBeforeCompileHead on the site and the administrator. For an HTML page it asks the task model whether any task is due and, only if one is, loads a small script with the configured interval. The script then calls com_ajax (plugin=RunSchedulerLazy) in the background and the plugin runs the scheduler, ignoring a client that has already left. The consequences are:

  • nothing runs on a site nobody visits, so a nightly task on a quiet club site may run late or not at all

  • a due task adds a little load to a visitor’s request cycle, and a visitor may notice a slight slowdown

  • the lazy endpoint carries no user check or key, so it can be triggered by anyone; that is acceptable because it only runs tasks that are already due

  • long tasks are limited by the web server’s execution limits

Use it for development and for small sites where timing does not matter.

Web cron

Web cron lets an external service or the hosting panel’s cron call a Joomla URL. Turn on Web Cron in the options; saving generates a 20-character key (reset it with Reset Access Key), and the options screen then shows the Webcron Link. The link has the shape described in the User Guide: the com_ajax endpoint with plugin=RunSchedulerWebcron&group=system&format=json and the key as the hash parameter. An optional id parameter selects one task. A request with web cron disabled, or with an empty or non-matching key, is answered with HTTP 403.

# Every minute from an external cron; keep the real key in the cron environment, not in the page source.
* * * * * curl --silent --fail "https://www.tallpine.example/component/ajax/?plugin=RunSchedulerWebcron&group=system&format=json&hash=${TALLPINE_CRON_HASH}" > /dev/null

Anyone who has the link can start tasks, so treat it as a secret and use Reset Access Key if it leaks, then update the cron. With web cron in place switch the lazy scheduler off; leaving both on can still slow visits now and then. Web cron works from any machine, uses the website’s PHP version and file owner, prevents a new task from starting while another is running, and is subject to the web server’s or host’s request time limit, often a minute or two.

System cron with the CLI

The command line is the most robust option when the host allows cron jobs. No option has to be switched on, no URL or key is needed, and there is no web time limit.

# crontab -e, as the user that owns the Joomla files (for example www-data)
* * * * * /usr/bin/php8.3 /var/www/tallpine/cli/joomla.php scheduler:run --all > /dev/null 2>&1

Points that cause real incidents:

  • PHP version. Give the full path to a supported PHP binary (PHP 8.3 or later for Joomla 6). The default php in a cron environment is often older than the web server’s.

  • File ownership. Run the job as the website user. A task such as Rotate Logs or Check Files that runs as root leaves files the web server then cannot overwrite.

  • Output. Appending > /dev/null 2>&1 stops cron from mailing every run’s output.

  • Overlap. The User Guide notes that the CLI route does not check for a running task, so a job that can outlast the cron interval should be safe to run twice or be scheduled less often. The scheduler itself also takes a per-task lock, described below.

The commands, run from the Joomla root (or with the full path to cli/joomla.php) are:

Command Effect

scheduler:run

Without options it starts only the next due task, so tasks wait for each other, one per invocation.

scheduler:run --all

Runs every task that is due.

scheduler:run --id=5

Runs the enabled task with ID 5 immediately, whether it is due or not.

scheduler:list

Lists the tasks with ID, state and next run time.

scheduler:state

Enables, disables or trashes a task. Check php cli/joomla.php scheduler:state --help for the exact arguments on your version.

More on the console in The Joomla CLI.

Which one to choose

Lazy scheduler Web cron System cron (CLI)

Setup

None

Enable in options, add an external cron

Add a cron job on the server

Timing

Only when visitors arrive

As precise as the cron interval

As precise as the cron interval

Time limit

Web server limit

Web server or host limit

None

Secret

None

Key in the URL

None

PHP and user

The site’s

The site’s

Whatever the cron job uses

Best for

Development, tiny sites

Shared hosting with a remote cron service

VPS, containers, long tasks

The recommendation of the User Guide is: precise timing with a remote cron means web cron plus the lazy scheduler switched off; long tasks on a server you control mean the command line. Older books such as Joomla! 4 Masterclass (2023) introduce the scheduler with the lazy mode only; for a production site that is the weakest choice.

Docker Compose

In a container the cron job belongs in its own service that runs the same image as the site, so PHP and the file layout match.

services:
  joomla:
    image: joomla:6.2-php8.4-apache
    volumes:
      - tallpine_site:/var/www/html
  scheduler:
    image: joomla:6.2-php8.4-apache
    volumes:
      - tallpine_site:/var/www/html
    working_dir: /var/www/html
    user: www-data
    entrypoint: ["/bin/sh", "-c"]
    command:
      - "while true; do php cli/joomla.php scheduler:run --all; sleep 60; done"
volumes:
  tallpine_site:

The site volume holds configuration.php, so the second service reaches the same database. The surrounding Compose file (MariaDB, Mailpit) is in Local development with Docker.

Creating and editing a task

System → Scheduled Tasks → New first asks for the task type, which is the list of routines contributed by enabled task plugins; a plugin that is disabled contributes no type, and a task whose plugin is later disabled becomes orphaned. The edit form (forms/task.xml) has these parts:

  • Title (required, 100 characters), Note and Status: enabled, disabled or trashed.

  • Execution rule: interval in minutes, hours, days or months, a cron expression, or manual execution only. A days interval takes a time; a months interval takes a day of the month (1 to 31) and a time. The cron expression is five fields (minutes, hours, days of month, months, days of week), useful to spread tasks so they do not all start at once. Manual tasks run only from the yellow Run Task button in the list or the CLI with --id.

  • Priority: Low (-1), Normal (0) or High (1). Due tasks are picked by priority first and then by the oldest next execution.

  • Logging: an individual log switch; when on, the task writes to its own file (by default task_ID.log.php) in the Joomla log folder, in addition to the general log under the category task plus its ID.

  • Read-only history: last and next execution, times executed, times failed and last exit code.

  • Permissions: the task’s ACL; the core.testrun action allows a user to run the task from the administrator, and the task’s creator may also test it while holding core.create.

Task-specific parameters live on the plugin’s own tab; for example the Delete Action Logs task asks for the retention in days.

Example: Tallpine nightly housekeeping

The club wants these tasks, all created from the administrator interface:

Task Rule Reason

Session Data Purge

Every 6 hours

Keep the session table small

Rotate Logs

Days: 1, at 02:30

Keep administrator/logs bounded

Delete Action Logs

Days: 1, at 03:00, retention 180

Privacy retention, see Privacy and action logs

Global Check-in

Hours: 1, delay 2 hours

Release articles left open by editors

Update Notification

Days: 1, at 07:00

Mail Super Users when a core update exists

Tallpine trail sync

Minutes: 30

Custom routine from plg_task_tallpine_trailsync

A cron expression equivalent to "every 6 hours starting at 05:00" is minutes 0, hours 5,11,17,23, any day, any month, any weekday.

The core task plugins

Joomla 6.2 ships nine task plugins in the task plugin group (plugins/task). Each exposes one routine, except Site Status, which exposes three. Behaviour below is taken from the plugin sources.

Check Files (checkfiles)

Routine checkfiles.imagesize. It scans a folder (a path relative to the site root, two directory levels deep) for jpg, jpeg, png, gif and webp images and, when the chosen side (width or height) exceeds the configured limit in pixels, shrinks the image in place keeping the aspect ratio. A maximum number of images per run keeps each execution short. The original is overwritten, so run it on a copy of images/ first. A folder that does not exist logs a warning and does not run; a failed resize ends with a failure status.

Delete Action Logs (deleteactionlogs)

Routine delete.actionlogs. The parameter logDeletePeriod is the number of days to keep; older rows are deleted from the action-logs table. A value of 0 or less deletes nothing and still reports success. A database error gives a failure status. This is the task that enforces the retention policy described in Privacy and action logs.

Global Check-in (globalcheckin)

Routine plg_task_globalcheckin_task_get. It checks in every table of the site (prefix included) that has both checked_out and checked_out_time columns, which is the same sweep as System → Global Check-in. With a delay in hours greater than zero only items checked out earlier than that are released; with zero or no value everything is released, including an article an editor is working on right now. A delay of a few hours is the safe setting.

Routine privacy.consent. It does two jobs in order. First it invalidates active consents older than the expiry in days and notifies the Super Users with the affected username. Then it sends a reminder to users whose consent expires within the reminder window (a mail template, with a link to the privacy component’s remind view and a token whose hash is stored). If a parameter is left empty its value is read as 0 rather than the documented default, so always fill in both the expiry and the reminder days. See Privacy and action logs.

Requests (requests)

Routine plg_task_requests_task_get. It sends an HTTP GET to a URL with a timeout, optionally with an Authorization header built from a type and a key, and saves the response body as task_ID_response.html under the Joomla root directory. Only status 200 is a success; any other status is a failure, and a transport exception is reported as a timeout. It supports no other method, headers or body, so it fits "ping this URL" jobs (warming a cache, hitting an external health check), not API integrations. The stored key sits in the task’s parameters and the target URL is not validated, so give task-editing permission only to trusted administrators and never point it at an address you do not control. A custom routine, as in plg_task_tallpine_trailsync, is the better tool for authenticated API work.

Rotate Logs (rotatelogs)

Routine rotation.logs. It renames .php files in the configured log path with a numeric prefix (error.php becomes 1.error.php, 1.error.php becomes 2.error.php), working from the highest number down, and deletes files whose number reaches the configured number of logs to keep. The parameter must be set: an empty value is read as 0, which deletes every log file. Set it to the number of generations you want to retain, for example 7 with a daily rule.

Session GC (sessiongc)

Routine session.gc, with two switches: Enable session garbage collection (calls the session handler’s GC) and Enable session metadata garbage collection (deletes metadata older than the session lifetime). Both default to disabled when absent from the task’s stored parameters, so open the task and save it with both on.

Site Status (sitestatus)

Three routines take no parameters: plg_task_toggle_offline (toggle), plg_task_toggle_offline_set_online and plg_task_toggle_offline_set_offline. Each rewrites configuration.php with the new value of the offline flag, adjusts permissions around the write and clears the OPcache entry. Used as a pair, two tasks give the Tallpine site a nightly maintenance window: one sets the site offline at 03:30, another online at 03:40. It needs configuration.php to be writable by the user running the scheduler, which conflicts with a hardened read-only configuration (see configuration.php and .htaccess); on a hardened site run it from the CLI as the file owner or do not use it.

Update Notification (updatenotification)

Routine update.notification. If a core update newer than the installed version exists it mails the Super Users, using the mail template plg_task_updatenotification.mail. Recipients are users with core.admin at the root who are not blocked and have system emails enabled; the optional Email parameter restricts that to the listed addresses that match eligible users, falling back to all eligible Super Users if none match. A language override forces the mail language. It stays quiet for a short time after an update check when automated core updates are subscribed. Edit the text with mail templates. It only notifies; the update itself is covered in Updating Joomla and Automated Core Updates.

Locking, timeouts and exit codes

Each task row has a locked timestamp. The scheduler takes the lock when it fetches the task, with a conditional update that succeeds only when the column is empty or older than the timeout option (300 seconds by default), and clears it when the routine finishes. This is why two overlapping triggers cannot run the same task at once, and why a crashed process (killed PHP, server restart) blocks its task only until the timeout has passed. If you have tasks that legitimately run for more than 300 seconds, raise the timeout or let the routine process work in batches and return the resume status.

A routine returns an integer status (the Status class):

Code Name Meaning

0

OK

Success.

2

NO_LOCK

The lock could not be acquired.

3

NO_RUN

The task could not run, for example a missing precondition.

4

NO_RELEASE

The lock could not be released or the record could not be updated.

5

KNOCKOUT

An exception stopped the routine.

123

WILL_RESUME

More batches remain; the task is rescheduled almost at once and counts as one execution after the last batch.

124

TIMEOUT

The routine timed out.

125

NO_TASK

The task does not exist.

127

NO_ROUTINE

The routine is missing, for instance because its plugin is disabled.

Anything other than OK or WILL_RESUME increases the task’s failure counter. Returning nothing yields -1 and a non-integer yields -2.

Monitoring

  • The task list shows state, last run, next run and last exit code. The Last Run Date column tells you quickly whether the trigger works at all; a task that never runs after the lazy scheduler was switched off usually means the cron job was never added or runs with the wrong PHP.

  • php cli/joomla.php scheduler:list shows the same from a shell, so it can be used in a health check.

  • Turn on the individual log of a critical task to get its own file, and read the general logs under the category task.

  • The scheduler component’s changes are written to the action log (component scheduler); see Privacy and action logs.

  • Test a task by hand with its Run Task button, or with scheduler:run --id=N as the web server user, before relying on its schedule.

# Health check for a monitoring system: fail when no task is listed for the Tallpine site
docker compose exec -T -u www-data joomla php cli/joomla.php scheduler:list
docker compose exec -T -u www-data joomla php cli/joomla.php scheduler:run --id=5

Common errors and pitfalls

  • Two triggers at once. Lazy and web cron or CLI together still work but waste work and slow visits; pick one.

  • Wrong PHP binary in cron. The cron job fails on syntax or missing extensions while the site works; use an explicit /usr/bin/php8.3.

  • Wrong user. Logs, rotated files or configuration.php end up owned by root.

  • Empty numeric parameters. Rotate Logs, Privacy Consent, Session GC and Global Check-in treat an unset value as 0, with effects ranging from nothing happening to deleting all logs. Always open and save every core task once and check its parameters.

  • Disabled plugin. A task whose plugin is disabled has no routine and fails with the missing-routine status.

  • Exposed key. A web cron URL in a shared ticket or a screenshot lets anyone run tasks; reset the key.

  • Behind a reverse proxy. A web cron request that is redirected (HTTP to HTTPS, missing www) can lose its query string or be answered by a cache; call the final HTTPS address directly and exclude the path from page caching.

Version notes

Scheduled Tasks arrived in Joomla 4.1 as com_scheduler, together with the task plugin group; the nine core task plugins above are present in 6.2. For authors of custom routines the 5.0 concrete event classes and the removal in 7.0 of the automatic $app and $db plugin properties matter (see Scheduled task plugins). The source tree of com_scheduler is the reference for internals and the User Guide is the reference for operation. Joomla 4 is end of life and 5.x is security-only; new sites should start on 6.2 (see Versions, release cycle and support).