Moodle plugin types are the fixed categories of extension that Moodle core knows how to load: each type has a short frankenstyle prefix (such as mod, block or local) and one directory where every plugin of that type lives. Moodle 5.3 defines 45 plugin types in lib/components.json, keeps one more (mnetservice) in a deprecated list, and core plugins declare a further 18 subplugin types of their own. Pick the wrong type and your code either never loads or fights the APIs it needs.
This reference lists every type with its directory, explains how subplugins work, shows which types arrived or left in recent releases, and gives a short rule set for choosing the right one. Checked against the Moodle 5.3.0 source (lib/components.json, every core db/subplugins.json, core_component and core_plugin_manager) and the Moodle developer docs on plugin types, October 2026.
How Moodle knows which plugin types exist
Moodle does not scan the disk for anything that looks like a plugin. It reads a registry, then looks only in the directories that registry names:
lib/components.jsonat the project root holds three objects:plugintypes(type to directory),subsystems(core areas such ascore_course) and, when needed,deprecatedplugintypesordeletedplugintypes.db/subplugins.jsoninside a plugin declares that plugin's own subplugin types under asubplugintypesobject, with directories relative to the parent plugin.core_componentloads both, then caches the result.core_component::get_plugin_types()returns every type and its full path,get_plugin_list($plugintype)returns the installed plugins of one type, andget_subplugins($component)returns a parent's subplugin types.
A new plugin folder is installed when an administrator visits the Notifications page or runs admin/cli/upgrade.php. If you need the exact list for your own site rather than this article, the developer docs give a short CLI script that loops over core_plugin_manager::instance()->get_plugin_types() and prints each type, its plural name from plugintype_name_plural() and its directory.
From Moodle 5.1 the web-accessible code moved into public/, so every directory below sits under public/ on 5.1, 5.2 and 5.3. On 5.0 and earlier, drop that prefix. components.json in 5.3 stores the paths with the prefix, for example "local": "public/local".
The plugin types most projects actually use
Most custom work lands in about a dozen types. This table maps the common needs to the type that fits.
| You want to | Plugin type | Directory (under public/) |
|---|---|---|
| Add a new activity teachers place in a course, with its own grades and completion | mod | mod |
| Show a panel on course, dashboard or site pages | block | blocks |
| Add site-wide behaviour, event observers, web services or pages that fit no other type | local | local |
| Log users in against an external identity source | auth | auth |
| Control how users get into courses (sync, payment, keys) | enrol | enrol |
| Change the look of the site | theme | theme |
| Change how a course page lays out sections and activities | format | course/format |
| Add a site or course report | report | report |
| Add an admin utility under Site administration | tool | admin/tool |
| Add a new question type for quizzes | qtype | question/type |
| Transform text as it is displayed | filter | filter |
| Add a new "Restrict access" condition | availability | availability/condition |
Every Moodle plugin type and its directory in Moodle 5.3
This is the full plugintypes object from the 5.3.0 lib/components.json, grouped by area. Directories are relative to public/.
| Area | Frankenstyle type and directory |
|---|---|
| Courses and activities | mod mod; block blocks; format course/format; availability availability/condition; customfield customfield/field |
| Questions | qtype question/type; qbehaviour question/behaviour; qformat question/format; qbank question/bank |
| Grades | gradeexport grade/export; gradeimport grade/import; gradereport grade/report; gradingform grade/grading/form; gradepenalty grade/penalty |
| Users and access | auth auth; enrol enrol; profilefield user/profile/field |
| Reports and admin | report report; coursereport course/report; tool admin/tool |
| Look and content | theme theme; filter filter; editor lib/editor; media media/player; contenttype contentbank/contenttype; h5plib h5p/h5plib |
| Files and exports | repository repository; portfolio portfolio; fileconverter files/converter; dataformat dataformat |
| Integration and messaging | webservice webservice; message message/output; communication communication/provider; paygw payment/gateway; smsgateway sms/gateway; plagiarism plagiarism; calendartype calendar/type |
| AI and analytics | aiprovider ai/provider; aiplacement ai/placement; mlbackend lib/mlbackend |
| Infrastructure | cachestore cache/stores; cachelock cache/locks; search search/engine; antivirus lib/antivirus |
| Everything else | local local |
A few of these surprise people. coursereport is still registered, but 5.3 ships no plugins in course/report; new course-level reports belong in report. editor covers whole text editors (TinyMCE and the plain textarea in 5.3), not editor buttons. h5plib holds versions of the H5P integration library, not H5P content.
Subplugin types: plugins inside plugins
Some plugins expose their own extension points. The parent declares them in db/subplugins.json, and the subplugin's component name uses the subplugin type as its prefix, for example assignsubmission_file. These are the 18 subplugin types declared by core plugins in 5.3.0:
| Parent | Subplugin type | Directory (under public/) |
|---|---|---|
| Assignment | assignsubmission, assignfeedback | mod/assign/submission, mod/assign/feedback |
| Quiz | quiz (reports), quizaccess | mod/quiz/report, mod/quiz/accessrule |
| Workshop | workshopform, workshopallocation, workshopeval | mod/workshop/form, mod/workshop/allocation, mod/workshop/eval |
| Database | datafield, datapreset | mod/data/field, mod/data/preset |
| External tool (LTI) | ltisource, ltiservice | mod/lti/source, mod/lti/service |
| Book | booktool | mod/book/tool |
| SCORM | scormreport | mod/scorm/report |
| Forum | forumreport | mod/forum/report |
| BigBlueButton | bbbext | mod/bigbluebuttonbn/extension |
| Logging (tool_log) | logstore | admin/tool/log/store |
| Multi-factor authentication (tool_mfa) | factor | admin/tool/mfa/factor |
| TinyMCE editor | tiny | lib/editor/tiny/plugins |
Third-party plugins can declare subplugin types too, so a site with contributed plugins will show more than this list. Subplugin type names are global: each subplugin type name must be unique across the site, because Moodle maps the prefix alone, such as quizaccess, to one directory.
A subplugin is usually the cleaner choice when you extend one activity. A new quiz access rule belongs in quizaccess, not in a local plugin that hooks into quiz pages, because the quiz then calls your rule through its own API.
Plugin types added, deprecated and removed in recent releases
If you maintain plugins across several Moodle branches, these changes matter more than the full list:
| Release | Change |
|---|---|
| 3.10 | Payment subsystem with the paygw gateway type (MDL-69166) |
| 4.0 | qbank question bank plugins |
| 4.3 | Communication subsystem with Matrix and custom link providers in communication/provider (MDL-77576, MDL-78619) |
| 4.5 | AI subsystem with aiprovider and aiplacement (MDL-82627); SMS subsystem with the smsgateway type (MDL-80960) |
| 5.0 | gradepenalty for generic grade penalties, shipped with gradepenalty_duedate (MDL-80984); Atto editor removed, so the atto subplugin type is gone (MDL-83282); MNet plugins removed (MDL-84652); plugin type deprecation mechanism added (MDL-79843) |
| 5.1 | Web code moved into public/; plugin types must define type_<type> and type_<type>_plural language strings (MDL-84948) |
In 5.3.0, mnetservice (public/mnet/service) is the only entry in deprecatedplugintypes, and there is no deletedplugintypes object. Deprecation is staged: in the first stage core stops calling plugins of that type through hooks, callbacks and events, though their classes and strings still load; in the second (deleted) stage, any installed plugin of that type blocks the site upgrade until it is uninstalled. Subplugin owners use the same stages through deprecatedsubplugintypes and deletedsubplugintypes. If you hit that block, our guide to an upgrade blocked by a deprecated plugin type walks through the fix.
Naming rules and frankenstyle component names
Every plugin has a frankenstyle component name: the type, an underscore, then the plugin's machine name, as in local_hrsync or block_myoverview. The machine name is checked by core_component::is_valid_plugin_name():
- It must start with a lowercase letter, end with a lowercase letter or digit, and contain only lowercase letters, digits and single underscores. The pattern is
/^[a-z](?:[a-z0-9_](?!__))*[a-z0-9]+$/. - Activity modules (
mod) may not contain underscores at all (the check is/^[a-z][a-z0-9]*$/), and a module may not share its name with a core subsystem. qtype_randomis reserved and rejected.- Hyphens are never allowed. A plugin that fails these checks is silently ignored, which is a common reason a freshly copied plugin never appears on the upgrade screen.
The folder name must match the machine name, and the component name drives the class namespace (\local_hrsync\...), the language file (lang/en/local_hrsync.php) and configuration rows. One quirk: activity modules keep a bare language file name (lang/en/forum.php for mod_forum).
How to choose the right plugin type
A few rules settle most debates on a project:
- Use the most specific type that has an API for your job. A new login method is
auth, a new payment provider ispaygw, a new AI model connector isaiprovider. The specific type plugs into the admin screens and callbacks core already has for that job. - Extend an activity through its subplugin type when one exists, rather than patching the activity or hooking into it from outside.
- Reach for
localwhen nothing else fits: integrations, scheduled sync jobs, event observers, web service functions and site-wide hooks. Do not use it to add a learner-facing course activity; that needsmodso it appears in the activity chooser, backup and restore, the gradebook and completion. - Use
toolfor admin-only utilities that live under Site administration, andreportfor read-only reporting screens. - Never edit core plugins. If a core plugin almost fits, look for a hook, a subplugin type or a theme override first, then a
localplugin.
Some features span types. A typical HR integration is a local plugin for the sync and web services plus an auth plugin for login. Ship each as its own plugin, declare the dependency in version.php, and keep shared code in one of them.
To see what a site already has, open Site administration, Plugins, Plugins overview, or run php admin/cli/uninstall_plugins.php --show-contrib from the project root to list third-party plugins only. Our Moodle guide covers the rest of the development and administration topics, and the plugin compatibility guide explains what to check before a major upgrade.
How we can help
We build and maintain Moodle plugins of every common type, from local integrations and auth connectors to full activity modules and quiz access rules, and we audit contributed plugins before upgrades. See our Moodle plugin development service or the wider Moodle platform page.
Frequently asked questions
How many plugin types does Moodle have?
Moodle 5.3.0 lists 45 plugin types in the plugintypes object of lib/components.json, plus mnetservice in the deprecated list. Core plugins add 18 subplugin types, and contributed plugins can declare more.
What is the difference between a local plugin and an admin tool?
A tool plugin lives in admin/tool and is meant for admin utilities under Site administration. A local plugin lives in local and is the general home for site-wide customisations, integrations, event observers and web services that fit no other type.
Where do plugins go in Moodle 5.1 and later?
Under the public/ directory, for example public/local/myplugin or public/blocks/myblock. On Moodle 5.0 and earlier the same paths sit directly in the web root.
Why does my Moodle plugin not show up after I copy it to the server?
Common reasons are a folder name that breaks the naming rules (hyphens, uppercase, or underscores in an activity module name), the wrong parent directory for its type, or a version.php component name that does not match the folder. Invalid names are silently ignored.
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
- Plugin types - Moodle HQ
- lib/components.json (Moodle 5.3.0) - Moodle HQ
- lib/classes/component.php (Moodle 5.3.0) - Moodle HQ
- Frankenstyle component names - Moodle HQ
- Moodle 4.5 release notes - Moodle HQ
- Moodle 5.0 release notes - Moodle HQ
Learn more about this topic with AI
Gemini opens with the prompt copied - paste it into the chat to start.