Moodle version.php is the small metadata file every plugin must have in its root directory. It tells Moodle the plugin's frankenstyle name ($plugin->component), its version number, the oldest Moodle it runs on (requires), the Moodle branches it supports or cannot run on (supported and incompatible), how stable the release is (maturity), a human-readable release name and any other plugins it depends on. Moodle reads it to decide whether a plugin needs installing or upgrading, and whether it is allowed to.
Two properties are mandatory in practice: component and version. Without either, the upgrade stops with a "defective" plugin error. The rest are optional but shape what administrators see on the Plugins check page and whether an install goes ahead.
Checked against the Moodle 5.3.0 source (public/lib/upgradelib.php, public/lib/classes/plugin_manager.php, public/lib/classes/plugininfo/base.php) and the version.php page in the Moodle developer documentation (October 2026).
A complete example
A local plugin that needs Moodle 5.0 or later and has been tested on 5.0 to 5.3:
<?php
// GPL header omitted for brevity.
/**
* Version information for local_example.
*
* @package local_example
* @copyright 2026 Your Name
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'local_example';
$plugin->version = 2026110300; // YYYYMMDDXX.
$plugin->requires = 2025041400.00; // Moodle 5.0.
$plugin->supported = [500, 503]; // Moodle 5.0 to 5.3.
$plugin->maturity = MATURITY_STABLE;
$plugin->release = '1.2.0';
$plugin->dependencies = [
'mod_forum' => ANY_VERSION,
];
Not run on a live site; test on staging first. The file holds assignments to $plugin and nothing else.
Property reference
| Property | Type | Needed? | What core does with it |
|---|---|---|---|
component | string | Yes | Must equal type_name for the directory the plugin sits in; otherwise the upgrade stops |
version | integer | Yes | Compared with the version stored in config_plugins to decide install, upgrade or downgrade |
requires | number | Recommended | Install or upgrade is refused if it is higher than the site's core $version |
supported | array of two integers | Optional (3.9+) | Shown as a branch range on the Plugins check page; a malformed value throws a coding exception |
incompatible | integer | Optional (3.9+) | Install or upgrade is refused when the site's branch is equal or higher |
maturity | constant | Recommended | Used by update notifications and the "Required code maturity" setting |
release | string | Recommended | Display only |
dependencies | array | Optional | Each listed plugin must be present at the given version or later |
version: the number that triggers upgrades
The format is YYYYMMDDXX: the release date plus a two-digit counter for that day. Moodle stores the installed value in config_plugins (plugin = your component, name = version) and compares it with the file on disk:
- No stored value: the plugin is new and is installed from
db/install.xml. - Disk higher than stored: the plugin is upgraded, running your
db/upgrade.phpsteps. - Disk lower than stored: the Plugins check page shows "Higher version already installed!" and the upgrade throws "Cannot downgrade ... from ... to ...".
Every release must increase the number. If you maintain several stable branches, the developer docs recommend freezing the date part at the branch point and using the XX counter on that branch, so that every newer branch starts with a higher YYYYMMDD00 than any older one. Get this wrong and a site moving between your branches hits the downgrade error; our article on the Moodle "Cannot downgrade" plugin error covers the recovery.
Each upgrade step in db/upgrade.php ends with a savepoint call (for example upgrade_plugin_savepoint()) carrying the step's version. Core refuses a savepoint that is not higher than the stored version, so two steps with the same number throw "Cannot downgrade". A step numbered above the value in version.php is just as bad: it stores the higher number, and from then on the file on disk looks older than the database. Bump version.php to at least the number of your newest upgrade step.
requires: the minimum Moodle version
requires is compared with core's $version from the root version.php. If it is higher, the upgrade stops with: "Plugin ... could not be installed. It requires a newer version of Moodle (currently you are using ..., you need ...)". A value below 2010000000 is treated as a pre-2.0 plugin and rejected as defective.
Use the exact core version number of the oldest release you support. These are the x.y.0 values from the Moodle source tags:
| Release | Core $version | $branch |
|---|---|---|
| Moodle 5.0 | 2025041400.00 | 500 |
| Moodle 5.1 | 2025100600.00 | 501 |
| Moodle 5.2 | 2026042000.00 | 502 |
| Moodle 5.3 | 2026100500.00 | 503 |
To find the number for any other release, open the root version.php of that release (in 5.1 and later it is public/version.php) and copy $version. Point releases increase it, so a plugin that needs a fix from 5.3.2 should require the 5.3.2 value, not the 5.3.0 one.
supported and incompatible: branch ranges
Both properties use branch numbers, not version numbers: 500 for 5.0, 503 for 5.3, 405 for 4.5. They were added in Moodle 3.9 (MDL-59562).
supported is an inclusive range, [lowest, highest]. In the 5.3 source, core validates its shape (exactly two integers, low not above high) and throws a coding exception otherwise. It then uses it for display: the Plugins check page shows "Moodle 500 - 503" in the requirements column. It does not block installation on a branch outside the range; the install and upgrade code checks only requires and incompatible.
incompatible is the first branch the plugin cannot run on. When the site's $CFG->branch is equal or higher, install and upgrade stop with "Plugin ... does not support this version of Moodle ...". Set it when you know a later branch breaks the plugin, for example after a Moodle release removes an API you depend on:
$plugin->supported = [500, 503];
$plugin->incompatible = 504; // Blocks Moodle 5.4 and later.
Be careful with incompatible: it blocks the whole site upgrade until the plugin is updated or removed. That is the right outcome for a plugin that would corrupt data on a newer branch, but it is a heavy tool for "not tested yet". Use supported to say what you tested. If an upgrade is already blocked, see Moodle plugin not compatible after upgrade.
maturity: what it controls
| Constant | Value | Admin label |
|---|---|---|
MATURITY_ALPHA | 50 | Alpha |
MATURITY_BETA | 100 | Beta |
MATURITY_RC | 150 | Release candidate |
MATURITY_STABLE | 200 | Stable version |
A plugin's maturity does not stop it installing. It feeds the update notification system: under Site administration > Server > Update notifications, the "Required code maturity" setting (default Stable version) hides available updates below that level. Per the setting's own description, updates for plugins that do not declare a maturity are always reported. When several updates are available, core prefers the most mature, and treats an undeclared maturity as between release candidate and stable. Declare it.
component and dependencies
component is the full frankenstyle name, such as local_example or mod_example. During upgrade, a missing value stops with "Missing $plugin->component declaration in version.php", and a value that does not match the directory stops with "Plugin ... is installed in incorrect location ..., expected location is ...". The usual cause is a zip extracted to the wrong folder or a renamed directory. Our guide to Moodle plugin types lists where each type must live.
dependencies maps other components to a minimum version, or to ANY_VERSION when any installed version will do. If a dependency is missing or too old, the Plugins check page marks the requirement as failed and the upgrade cannot continue.
Rules for the file itself
- No includes. The developer docs state that version.php must never contain
require_onceor any other file inclusion. Core reads it with a plainincludefrom several places, including the check that decides whether the site needs upgrading, so it has to stay a side-effect-free data file. Declaring a function or class there can also cause a "cannot redeclare" fatal error when the file is read twice in one request. - Start with the guard.
defined('MOODLE_INTERNAL') || die();stops direct web access. - Use
$plugin, not$module. In 5.3, the plugin manager prints a debugging message when the old activity-module$modulesyntax is used. - Literal values only. No conditions, no reading config. The file must give the same answer every time it is read.
Common mistakes and the errors they cause
| Mistake | What you see |
|---|---|
| Version not increased after a schema change | No upgrade runs; new tables or fields are missing |
| Version lower than an earlier release | "Cannot downgrade ..." |
requires set to a newer core than the site | "It requires a newer version of Moodle ..." |
supported with three values or strings | Coding exception: incorrect syntax in plugin supported declaration |
incompatible set to the current branch | "... does not support this version of Moodle ..." |
component does not match the folder | "... is installed in incorrect location ..." |
For the wider development workflow, including upgrade code and testing, start with our Moodle guide.
How we can help
We build and maintain Moodle plugins across several stable branches, including version numbering, upgrade steps and CI against each supported release. See our Moodle plugin development service or tell us about your plugin.
Frequently asked questions
What is version.php in Moodle?
It is the mandatory metadata file in the root of every Moodle plugin. It sets the plugin's component name, version number, minimum Moodle version, supported branches, maturity, release name and dependencies, which Moodle uses during install and upgrade.
What is the difference between requires and supported in Moodle version.php?
requires is a single core version number (for example 2026100500.00 for Moodle 5.3) and installation is refused on older sites. supported is a pair of branch numbers such as [500, 503] showing the tested range; in Moodle 5.3 it is displayed on the Plugins check page but does not block installation.
How do I find the Moodle version number for requires?
Open the root version.php of the Moodle release you want as the minimum (public/version.php in 5.1 and later) and copy the $version value. Use the point release you actually need, because point releases have higher numbers.
Can I use require_once in Moodle version.php?
No. The Moodle developer docs say version.php must never contain require_once or any other file inclusion. Core reads the file in performance-sensitive paths, so it must contain only assignments to $plugin.
What does $plugin->maturity do?
It declares how stable the release is (alpha, beta, release candidate or stable). It does not stop installation; it controls which available updates are reported, based on the Required code maturity setting under Site administration > Server > Update notifications.
Free 30-minute consultation
Not sure where to start? Talk to an LMS engineer.
Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.
Sources & references
- version.php - Moodle developer documentation
- Common files - Moodle developer documentation
- Moodle 5.3.0 upgradelib.php - Moodle (GitHub)
- MDL-59562: plugin supported and incompatible versions - Moodle Tracker
Learn more about this topic with AI
Gemini opens with the prompt copied - paste it into the chat to start.