Skip to main content
Extensions in Joomla
On this page

Extensions in Joomla

01 June 2026

A Joomla site is not one big program. It is the Joomla core plus a stack of extensions. An extension is the umbrella word for everything you can add to Joomla: components, modules, plugins, templates, languages, and the packaging that bundles them together.

This is the idea that connects the five extension types you may already know. They are not five unrelated things. They are all kinds of extension, and they share the same rules: a manifest file that describes them, a row in one database table that records them, and one installer that puts them in place and keeps them updated.

Components, modules, plugins, templates, languages and the machinery underneath: the manifest, the installer, and the one table that records them all.

This article explains how extensions really work. It covers the basics for website owners, the practical management screens for administrators, and the technical details for developers. You will learn what an extension is, how Joomla stores it, what the manifest does, how installing and updating work, and how to keep your extensions secure.

The goal is simple: help you understand Joomla extensions well enough to install, update, and troubleshoot them with confidence.

1. The Basics

1.1 What "Extension" Actually Means

Almost everything in the Joomla backend is an extension, and so is most of what you install from elsewhere. A simple test works well:

If you can install it, enable it, or uninstall it, then it is an extension.

Joomla is the platform. Extensions are everything you bolt onto it. The core CMS provides the framework, the application, and the shared libraries. Every functional thing on a page is delivered through an extension that the installer manages.

            +--------------------------------------+
            |          JOOMLA CORE (CMS)           |
            |   framework . application . libraries|
            +--------------------------------------+
                              ^
            installed & managed | through one pipeline
                              |
   +----------+----------+----+-----+-----------+-----------+
   | Component|  Module  |  Plugin  | Template  | Language  |  ...packages
   |  com_    |  mod_    |  plg_    |  tpl_     |   xx-XX   |   pkg_, lib_, file
   +----------+----------+----------+-----------+-----------+

1.2 The Five Functional Types

These five are the extension types that do something visible on a page. You have probably met each of them already:

TypeRolePer pagePrefix
Component Main page content or application exactly 1 com_
Module Small boxes around the content many mod_
Plugin Event-driven behaviour in the background many plg_
Template Look, feel, and page layout 1 site + 1 admin tpl_
Language Translations 1 active xx-XX

But the extension family is bigger than five. The rest are about packaging and support.

1.3 The Full Taxonomy

Joomla's installer recognises more type values than just the visible five. The extra ones are the "glue" that helps you ship and reuse code:

TypePrefixWhat it is
component com_ A mini-application, the engine of the page
module mod_ A reusable box on the page
plugin plg_ An event listener
template tpl_ Page look and layout
language xx-XX A translation pack
package pkg_ A bundle of several extensions installed together
library lib_ Shared PHP code reused by other extensions
file  - Loose files dropped into specific folders (for example the core "Joomla! Files")

A real-world product, such as a forum or a webshop, usually ships as one pkg_ package that contains a component, several plugins, and a few modules.

1.4 You Already Run Dozens of Extensions

A brand-new Joomla 6 install ships with around 150 extensions out of the box. Open System → Manage → Extensions and you will see them all: components like com_content, every core plugin, both default templates, the English language pack, and the libraries underneath.

There is no "core versus extensions" wall. Core Joomla is delivered as extensions. They are simply marked protected, so you cannot remove them by accident.

On top of the core set, the Joomla Extensions Directory (JED) lists thousands of third-party extensions you can add. Well-known examples include Akeeba Backup for backups, the Regular Labs content tools, and JCE for a richer editor.

Back to top

2. The #__extensions Table

2.1 One Table Records Every Extension

Whatever the type, every installed extension is exactly one row in the #__extensions table. This single table is the registry of your whole site. The #__ is Joomla's table prefix placeholder; on a real site it might be jos_extensions.

ColumnMeaning
extension_id Primary key
name Internal name (com_content, plg_content_joomla)
type component / module / plugin / template / language / package / library / file
element The element name (com_content, joomla, protostar)
folder Plugins only - the plugin group (content, system...)
client_id 0 = site, 1 = administrator
enabled 1 / 0
access View access level
protected 1 = cannot be uninstalled (core)
locked 1 = cannot be disabled or edited
manifest_cache JSON snapshot of the manifest (version, author...)
params JSON - the extension's saved Options

2.2 What Makes an Extension Unique

No single column identifies an extension. It is a combination of four columns:

type + element + folder + client_id  =  one unique extension

A few real examples show why all four are needed:

component | com_content | (none)  | 1   → the Articles admin app
module    | mod_menu    | (none)  | 0   → the site menu module
module    | mod_menu    | (none)  | 1   → the admin menu module   (same element, different client)
plugin    | joomla      | content | 0   → plg_content_joomla
plugin    | joomla      | user    | 0   → plg_user_joomla        (same element, different folder)

This is why plugins carry a folder (their group) and why the same module element can exist twice: once for the site, once for the administrator.

2.3 manifest_cache and params

Two JSON columns do a lot of work:

  • manifest_cache is a cached copy of the manifest's metadata: version, author, creation date, and description. The Manage list reads this, so it never has to re-parse the XML on every page load.
  • params holds the extension's Options. The "Options" button on any component, the settings on a plugin, the parameters of a module - all of them are serialised here as JSON.

When you click Options on any extension, you are editing the params JSON in this row. There is no separate config table.

Back to top

3. The Manifest: The Heart of Every Extension

3.1 The Self-describing XML File

Every extension contains one manifest: an XML file that tells Joomla everything about it. The installer reads nothing else first. Hand Joomla a zip with a manifest, and it knows how to install the extension, where its files go, what database tables to create, and how to update it later.

<extension type="component" method="upgrade">
    <name>com_example</name>
    <version>1.0.0</version>
    <creationDate>2026-06-01</creationDate>
    <author>Peter Martin</author>
    <namespace path="src">Joomla\Component\Example</namespace>

    <files folder="site">...</files>            <!-- which files to copy -->
    <media destination="com_example">...</media> <!-- images, css, js -->
    <languages>...</languages>                   <!-- translation files -->

    <install><sql>...</sql></install>            <!-- run on install -->
    <update><schemas>...</schemas></update>       <!-- run on update -->
    <uninstall><sql>...</sql></uninstall>        <!-- run on remove -->

    <scriptfile>script.php</scriptfile>         <!-- custom install logic -->
    <updateservers>...</updateservers>           <!-- where updates live -->
    <config>...</config>                         <!-- the Options form -->
</extension>

One file drives install, update, uninstall, configuration, and updates. Change the type attribute and the same structure describes a module, plugin, template, or package.

3.2 The Attributes That Change Everything

A few attributes on the root <extension> element decide how the installer behaves:

AttributeValuesEffect
type component, module, plugin, template, language, package, library, file What kind of extension this is - decides where files go
method install / upgrade upgrade overwrites existing files if already installed (the modern default)
group for example content, system Plugins only - which group or folder to install into
client site / administrator Modules and templates - which application it belongs to

method="upgrade" is why re-installing the same zip updates in place instead of failing with an "already installed" error.

3.3 The Install Script: Custom Logic

For anything the manifest's declarative tags cannot express, an extension can ship a script file with up to five methods:

class com_exampleInstallerScript
{
    public function preflight($type, $parent)  { /* before files are copied */ }
    public function install($parent)           { /* fresh install only      */ }
    public function update($parent)            { /* update only             */ }
    public function uninstall($parent)         { /* on removal              */ }
    public function postflight($type, $parent) { /* after files are copied   */ }
}
MethodRuns
preflight Before copying - version checks, abort if requirements are not met
install / update / uninstall The matching action only
postflight After copying - seed data, show a welcome message, clean up

Use preflight to block installation on an unsupported PHP or Joomla version by returning false.

3.4 Installer Events: Plugins That Hook Install and Update

The script file affects only its own extension. But the installer also fires events that any enabled plugin can listen to. This lets a plugin react when something else is installed, updated, or removed.

EventFires when
onExtensionBeforeInstall / onExtensionAfterInstall Around installing any extension
onExtensionBeforeUpdate / onExtensionAfterUpdate Around updating any extension
onExtensionBeforeUninstall / onExtensionAfterUninstall Around removing any extension
onInstallerBeforePackageDownload Just before a package is downloaded (for example to inject a download key)
// A commercial vendor's plugin injects its subscription key into the download URL:
public function onInstallerBeforePackageDownload(&$url, &$headers)
{
    if (str_contains($url, 'example.org')) {
        $url .= '&key=' . $this->params->get('download_key');
    }
}

This is exactly how paid extensions add a download or subscription key at update time: an ordinary installer plugin listening to these events, with no change to com_installer.

Back to top

4. Installing Extensions

4.1 com_installer: The Install and Update Component

Everything in this article is managed by one core component, com_installer, surfaced under the System menu:

System
 +-- Install → Extensions      (add new)
 +-- Manage  → Extensions      (enable / disable / uninstall, see all rows)
 +-- Update  → Extensions      (pending updates)
 +-- Manage  → Database        (schema check & fix)
 +-- Manage  → Discover        (find files already on disk)
 +-- Manage  → Warnings        (environment issues)

4.2 The Four Ways to Install

MethodHowWhen
Upload Package File Drag-and-drop or pick a .zip The normal way - you have the file
Install from Folder Give a server path to an unzipped folder Large extensions, or files uploaded by FTP
Install from URL Paste a direct link to a .zip The vendor gives a download URL
Install from Web Browse the JED inside Joomla and install with one click Discoverability - search the directory in place

"Install from Web" talks to the Joomla Extensions Directory through the Install from Web plugin. It is the app-store experience built into the backend.

4.3 What "Install" Actually Does

Handing Joomla a zip starts a fixed sequence:

 1. Unzip to a temp folder
 2. Find & parse the manifest  →  read type, files, sql, scriptfile
 3. preflight()                →  may abort
 4. Copy files to their homes  →  components/, modules/, plugins/, media/
 5. Run install SQL            →  CREATE TABLE #__example...
 6. Register the PSR-4 namespace
 7. Write the #__extensions row + manifest_cache
 8. Register update sites
 9. postflight()               →  seed data, messages
10. Clean up the temp folder

If any step fails, Joomla rolls back. No half-installed extension is left behind.

4.4 Discover: Installing What Is Already on Disk

Sometimes files arrive without going through the installer: an FTP upload, a git checkout, or a copied folder. They exist on disk but have no #__extensions row, so Joomla ignores them.

Manage → Discover  →  scans the standard folders for un-registered manifests
                     →  lists them  →  you click Install  →  rows are created

Discover is the bridge between "files on disk" and "an extension Joomla actually knows about". No file copying happens; it only creates the missing database rows.

4.5 Database: Keeping the Schema in Sync

The Manage → Database screen compares the SQL update files in each extension against what is actually in your database.

  • It detects tables or columns that should exist after an update but do not.
  • A Fix button replays the missing schema changes.
  • This is common after a manual file update where the SQL never ran, or after an interrupted update.

A red "Database schema is out of date" warning almost always means: go here and click Fix.

4.6 #__schemas: The Schema Version Log

How does the Database screen know a table is out of date? It compares each extension's SQL update files against a recorded version in #__schemas.

#__schemas
 +-- extension_id        | version_id
 +-- 27 (com_content)    | 6.0.0
 +-- 10000 (com_example) | 1.1.0
  • Each extension's update folder holds SQL files named after versions, for example sql/updates/mysql/1.1.0.sql.
  • After running them, Joomla writes the highest applied version into #__schemas.
  • On the next update it runs only the SQL files newer than the stored version. This is the migration "high-water mark".

So #__extensions.manifest_cache stores the file version, while #__schemas stores the database version. When the two disagree, that is the "schema out of date" warning, and the Fix button replays the missing SQL.

Back to top

5. The Update System

5.1 Update Sites: How Joomla Knows an Update Exists

Each extension can register one or more update sites: URLs that Joomla polls to ask "is there a newer version?". They live in #__update_sites, linked to extensions through #__update_sites_extensions.

#__extensions --< #__update_sites_extensions >-- #__update_sites
   (com_example)                                  (https://.../update.xml)

The update site is declared in the manifest:

<updateservers>
    <server type="extension" name="Example Updates">
        https://example.org/updates/com_example.xml
    </server>
</updateservers>

No update site means Joomla can never offer an update for that extension. This is why some manually-installed extensions never show an update notice.

5.2 The Update Server XML

The URL points to an XML file the vendor hosts. There are two flavours:

TypeDescribesUse
extension Available versions of a single extension One product
collection A list of extension update manifests A vendor with multiple products

Extension update manifest example:
<updates>
    <update>
        <name>com_example</name>
        <version>1.1.0</version>
        <infourl>https://example.org/changelog</infourl>
        <downloads>
            <downloadurl type="full" format="zip">
                https://example.org/dl/com_example-1.1.0.zip
            </downloadurl>
        </downloads>
        <targetplatform name="joomla" version="6.[01]" />
        <php_minimum>8.1</php_minimum>
    </update>
</updates>

Collection update manifest example
A collection manifest contains references to one or more extension update manifests. Each extension listed in the collection has its own extension update manifest.

<?xml version="1.0" encoding="utf-8"?>
<extensionset name="Example Extensions">
<extension>
<name>com_example</name>
<updateservers>
<server type="extension" priority="1" name="com_example">
https://example.org/updates/com_example.xml
</server>
</updateservers>
</extension>

<extension>
<name>com_another_example</name>
<updateservers>
<server type="extension" priority="1" name="com_another_example">
https://example.org/updates/com_another_example.xml
</server>
</updateservers>
</extension>
</extensionset>

The targetplatform and php_minimum elements allow a vendor to provide different update packages for specific Joomla or PHP versions from the same update site.

5.3 The Update Flow

Cron / page load / "Check for updates"
   |
   v
Joomla fetches each update site's XML
   |
   v
Compares the advertised <version> with the installed version
   |
   v
Newer? → row in #__updates  → shown under Update → Extensions
   |
   v
You click Update → Joomla downloads the <downloadurl> zip
   |
   v
...and runs the exact same install pipeline (method="upgrade")

An update is simply an install of a newer zip over the top: the same manifest, the same SQL-update step, the same rollback safety.

5.4 Joomla! Update versus Extension Updates

These are two separate things, and people often confuse them:

Joomla! UpdateExtension updates
Component com_joomlaupdate com_installer
Updates The CMS core itself Your installed add-ons
Source Joomla's official update server Each extension's own update site
Where System → Update → Joomla System → Update → Extensions

Keep both current. A modern, patched core with an outdated, vulnerable extension is still a vulnerable site.

Back to top

6. Packages: Bundling Extensions

6.1 Why Packages Exist

Most real products are more than one extension. A webshop might need a component (the store), plugins (payment, search), and modules (cart, featured products). Shipping eight separate zips is painful, so they are wrapped in one pkg_ package.

pkg_shop.zip
 +-- pkg_shop.xml              <- the package manifest
 +-- com_shop.zip              <- child: the component
 +-- plg_system_shop.zip       <- child: a plugin
 +-- plg_search_shop.zip       <- child: a plugin
 +-- mod_shop_cart.zip         <- child: a module
 +-- mod_shop_featured.zip     <- child: a module

6.2 The Package Manifest

A package manifest mostly just lists its children and the order in which to install them:

<extension type="package" method="upgrade">
    <name>Shop Package</name>
    <packagename>shop</packagename>
    <version>2.0.0</version>

    <files>
        <file type="component" id="com_shop">com_shop.zip</file>
        <file type="plugin" group="system" id="shop">plg_system_shop.zip</file>
        <file type="module" client="site" id="mod_shop_cart">mod_shop_cart.zip</file>
    </files>
</extension>
FeatureEffect
One install Installs every child in the listed order
One uninstall Removes all children together
One update site Update the whole bundle at once
Own #__extensions row type=package - the parent record

Uninstalling the package removes its children too. A child marked with <block> in the manifest can be protected from individual removal.

Back to top

7. Managing and Securing Extensions

7.1 The Manage Screen: Your Control Panel

System → Manage → Extensions lists every row in #__extensions:

ActionEffect
Enable / Disable Toggles enabled - disabled extensions do not run
Uninstall Removes files, runs uninstall SQL, deletes the row
Filter By type, by location (site or admin), by status
Protected badge Core - cannot be uninstalled
Locked badge Cannot be disabled or edited

protected and locked are why you cannot cripple your site by accident, for example by disabling com_content or removing the default language.

7.2 The Warnings Tab

Manage → Warnings surfaces environment problems the installer detected: missing PHP extensions, unwritable folders, or leftover files from a failed install. Check it when an install "succeeded" but the extension misbehaves.

7.3 Security: The Part That Bites People

Extensions run with full access to your site. A malicious or abandoned extension is the most common way Joomla sites get compromised.

PracticeWhy
Install only from trusted sources Prefer the JED; avoid "nulled" or pirated copies, which often contain malware
Keep everything updated Most hacks exploit a known, patched vulnerability in an outdated extension
Watch the JED VEL The Vulnerable Extensions List publishes known-bad extensions
Remove what you do not use Disabled is not enough - uninstall dead extensions; less code means less attack surface
Check it is maintained An extension with no update in years is a liability
Least privilege Do not grant extensions or their users more ACL than they need

The Joomla CMS core has a strong security track record. The weak link is almost always a third-party extension that was not updated.

7.4 Picking the Right Type to Build

When you need to extend Joomla yourself, choose the type by the job:

You want to...Build a...
Produce the main page content or a new app Component (com_)
Show a reusable box around the content Module (mod_)
React to an event or change behaviour Plugin (plg_)
Change the look and page layout Template (tpl_) - or a template override
Translate strings Language pack
Ship several of the above together Package (pkg_)
Share code between your own extensions Library (lib_)

The honest first question is often "do I even need a new extension?". A template override, a custom field, or a language override solves many needs with zero code to maintain.

Back to top

8. Extensions and the Shared Services

8.1 Extensions Do Not Reinvent: They Opt In

The deepest lesson across this whole series is that extensions are powerful precisely because they share Joomla's central services instead of duplicating them.

Shared serviceProvided byAny extension can...
Categories com_categories Organise its items in one shared hierarchy
Custom Fields com_fields Gain extra fields with no code
Tags com_tags Tag items across components
ACL #__assets Inherit site-wide permissions
Languages language packs Be fully translatable
// A component opts INTO the shared category service in services/provider.php
$container->registerServiceProvider(new CategoryFactory('\\Joomla\\Component\\Example'));

An extension that consumes the shared Categories service instantly gets a nested hierarchy, ACL inheritance, and multilingual support - all for free. That shared service is a topic worth a focus of its own.

Back to top

9. Common Mistakes and Pitfalls

9.1 Disabling Instead of Uninstalling

Disabling an extension stops it from running, but the code stays on disk and in the database. For security, that is not enough. If you no longer use an extension, uninstall it so its files and tables are removed.

9.2 Forgetting the Update Site

If you install an extension manually and it never shows an update notice, it probably has no update site registered. Check System → Update → Update Sites. An extension without an update site will silently stay on its old version.

9.3 Ignoring the Schema Warning

A "Database schema is out of date" warning is not cosmetic. It means an SQL migration did not run, often after a manual file update or an interrupted update. Go to Manage → Database and click Fix before strange bugs appear.

9.4 Installing from Untrusted Sources

"Nulled" or pirated copies of commercial extensions are a leading source of malware. The money you save is small compared to the cost of a hacked site. Always download from the developer or the JED.

9.5 Updating the Core but Not the Extensions

Many site owners run Joomla! Update faithfully but forget that extensions update separately. A patched core does not protect you from a vulnerable add-on. Check System → Update → Extensions as well.

9.6 Copying Files Without Discover

Uploading an extension's folder by FTP does not install it. Joomla only "knows" an extension when it has a #__extensions row. After uploading files, run Manage → Discover to register them, or simply install the zip the normal way.

Back to top

10. Best Practices

If you only remember a few things from this article, remember these:

  • Treat every component, module, plugin, template, and language as the same kind of thing: an extension.
  • Install only from the JED or directly from the developer.
  • Keep both the Joomla core and every extension up to date.
  • Uninstall extensions you no longer use - disabled is not enough.
  • Fix schema warnings as soon as they appear.
  • When building, ask first whether an override or a custom field is enough before writing a new extension.
  • Reuse Joomla's shared services (Categories, Fields, Tags, ACL) instead of reinventing them.
Back to top

11. Quick Reference

INSTALL      System → Install → Extensions (Upload / Folder / URL / Web)
MANAGE       System → Manage → Extensions (enable / disable / uninstall)
UPDATE       System → Update → Extensions
CORE UPDATE  System → Update → Joomla (separate from extensions)
DISCOVER     Manage → Discover  (register files already on disk)
SCHEMA FIX   Manage → Database  (replay missing SQL)
WARNINGS     Manage → Warnings  (environment problems)
REGISTRY     Every extension = one row in #__extensions
UNIQUE BY    type + element + folder + client_id
OPTIONS      Stored as JSON in #__extensions.params
Back to top

12. Summary

In Joomla, "extension" is the umbrella word for everything you add to the CMS - and core Joomla itself ships as extensions. The famous five (component, module, plugin, template, language) are joined by the packaging types: package, library, and file.

Once you see the shared machinery, every type makes sense:

  • One table: every extension is a single row in #__extensions, identified by type + element + folder + client_id.
  • One manifest: a self-describing XML file drives install, update, uninstall, configuration, and where updates come from.
  • One installer: com_installer runs the same pipeline for core and third-party code, with Discover, Database fix, and Warnings as its tools.
  • One update model: an update is just an upgrade install of a newer zip, separate from Joomla! Update for the core.
  • One safety rule: install from trusted sources, keep everything updated, and remove what you do not use.

Great extensions opt into Joomla's shared services - Categories, Fields, Tags, ACL, and Languages - instead of reinventing them. That is what makes the Joomla ecosystem fit together so well.

If you are planning a new Joomla site, troubleshooting an extension that misbehaves, or worried that an outdated add-on is putting your site at risk, it pays to understand how extensions work. They are the building blocks of every Joomla site.

Back to top
Extensions in Joomla
Peter Martin

Joomla en Linux specialist voor snelle, veilige en schaalbare websites.