If your Joomla extension still contains lines like JFactory::getUser(), JFactory::getDbo(), or JHtml::_(), you have a problem — and that problem has a deadline. With Joomla 7 development now officially underway, the deprecated code that's been accumulating since Joomla 4.0 is finally being removed. Extensions that haven't been updated will simply break.

JFactory has been Joomla's workhorse since version 1.5. For nearly 15 years, developers reached for it instinctively — it was everywhere, it was easy, and it worked. But "easy" came at a cost: static god classes are bad for testing, bad for architecture, and incompatible with modern PHP practices. Joomla 4 introduced a proper dependency injection container as the replacement. Joomla 7 finishes the job by removing JFactory and its family of static helpers entirely.

This guide gives you everything you need to migrate: the complete replacement cheatsheet, the right way to use Joomla's DI container, a practical audit process, and a real migration walkthrough. By the end, your extension will be ready for Joomla 7 — and it'll be cleaner and more maintainable than before.


What is JFactory and Why Is It Being Removed?

JFactory is a static factory class that first appeared in Joomla 1.5. Its job was simple: give developers a single, globally accessible entry point to core Joomla services. Need the current user? JFactory::getUser(). Need the database? JFactory::getDbo(). Need the application object? JFactory::getApplication().

The problem is that static classes are fundamentally incompatible with good software design:

  • Not testable. You can't mock a static class in unit tests. Extensions built around JFactory are nearly impossible to test properly.
  • Hidden dependencies. When your class calls JFactory::getDbo() buried inside a method, that dependency is invisible from the outside. It can't be swapped or overridden.
  • Global state. Static calls reach into global state, making behavior unpredictable and hard to reason about.
  • PHP modernization. Modern PHP development — and the broader ecosystem of tools, frameworks, and standards it's built around — uses dependency injection as the standard approach.

Joomla 4.0 marked JFactory as deprecated and introduced a proper DI container as the alternative. Joomla 5.x maintained backward compatibility to give developers time to migrate. With Joomla 7, the grace period ends. The June 6, 2026 maintenance sprint began the removal process — over 100 deprecation notices cleared in a single day, with more sprints planned.

The good news: the modern replacements are better in every way. Once you understand the pattern, migration is straightforward.


The Complete JFactory Replacement Cheatsheet

Here is every common JFactory call and its correct Joomla 7 replacement. Bookmark this — it's the most practical reference you'll need during migration.

Core JFactory Replacements

Get the current user

// Old — breaks on Joomla 7
$user = JFactory::getUser();

// Modern
$user = Factory::getApplication()->getIdentity();

// Best (DI injection in constructor)
public function __construct(private CMSApplicationInterface $app) {}
$user = $this->app->getIdentity();

Get the database connection

// Old — breaks on Joomla 7
$db = JFactory::getDbo();

// Modern (DI injection — preferred)
use Joomla\Database\DatabaseInterface;

public function __construct(private DatabaseInterface $db) {}
// $this->db is now available throughout the class

Get the application

// Old — breaks on Joomla 7
$app = JFactory::getApplication();

// Modern
$app = Factory::getApplication();

// Best (DI)
public function __construct(private CMSApplicationInterface $app) {}

Get the configuration

// Old — breaks on Joomla 7
$config = JFactory::getConfig();

// Modern
$config = Factory::getApplication()->getConfig();

Get the document

// Old — breaks on Joomla 7
$document = JFactory::getDocument();

// Modern
$document = Factory::getApplication()->getDocument();

Get the language

// Old — breaks on Joomla 7
$lang = JFactory::getLanguage();

// Modern
$lang = Factory::getApplication()->getLanguage();

Get the session

// Old — breaks on Joomla 7
$session = JFactory::getSession();

// Modern
$session = Factory::getApplication()->getSession();

Helper Class Replacements

JFactory isn't the only thing being removed. Its companion static helper classes are going too:

HTML helpers

// Old — breaks on Joomla 7
JHtml::_('form.token');
JHtml::_('jquery.framework');

// Modern
use Joomla\CMS\HTML\HTMLHelper;
HTMLHelper::_('form.token');
HTMLHelper::_('jquery.framework');

Language / Text

// Old — breaks on Joomla 7
JText::_('COM_MYEXTENSION_KEY');
JText::sprintf('COM_MYEXTENSION_FORMAT', $value);

// Modern
use Joomla\CMS\Language\Text;
Text::_('COM_MYEXTENSION_KEY');
Text::sprintf('COM_MYEXTENSION_FORMAT', $value);

Routing

// Old — breaks on Joomla 7
$url = JRoute::_('index.php?option=com_myext&view=item&id=1');

// Modern
use Joomla\CMS\Router\Route;
$url = Route::_('index.php?option=com_myext&view=item&id=1');

URI

// Old — breaks on Joomla 7
$base = JUri::base();
$root = JUri::root();

// Modern
use Joomla\CMS\Uri\Uri;
$base = Uri::base();
$root = Uri::root();

Notice the pattern: in most cases, the migration is simply dropping the J prefix and adding the correct use import. The deeper change — and the more important one — is switching to dependency injection wherever possible.


The Right Way: Using Joomla's DI Container

The cheatsheet above will fix your immediate compatibility issues. But if you want your extension to be truly modern and future-proof, dependency injection is the right long-term pattern — not just swapping JFactory for Factory.

Dependency injection means your class declares what it needs rather than going out and fetching it. Here's what that looks like in a Joomla 4+ component model:

Old approach (anti-pattern):

class MyModelItems extends ListModel
{
    public function getItems()
    {
        $db = JFactory::getDbo(); // hidden dependency, not testable
        $user = JFactory::getUser(); // hidden dependency

        $query = $db->getQuery(true);
        // ...
    }
}

Modern approach (DI):

use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\DatabaseInterface;
use Joomla\CMS\Application\CMSApplicationInterface;

class MyModelItems extends ListModel
{
    public function __construct(
        array $config,
        MVCFactoryInterface $factory,
        private DatabaseInterface $db,
        private CMSApplicationInterface $app
    ) {
        parent::__construct($config, $factory);
    }

    public function getItems()
    {
        $user  = $this->app->getIdentity(); // explicit, injectable
        $query = $this->db->getQuery(true); // explicit, injectable
        // ...
    }
}

With DI, your dependencies are visible, swappable, and testable. You can pass a mock database in tests. You can see exactly what a class needs just by looking at its constructor. This is how modern PHP works — and how Joomla 7 expects extensions to be built.

Joomla's service provider system handles wiring everything together. Define your services in a services/provider.php file and the container takes care of injecting the right objects automatically.


How to Audit Your Extension for Deprecated Code

Before you can fix deprecated code, you need to find it. Here's a systematic audit process:

1. Search Your Codebase

Run a search across your extension's files for all deprecated patterns. If you have terminal access:

# Find all JFactory calls
grep -r "JFactory::" /path/to/your/extension/

# Find J-prefixed helper classes
grep -r "JHtml\|JText\|JRoute\|JUri\|JLoader\|JLog\|JMail" /path/to/your/extension/

# Find old import patterns
grep -r "jimport\(" /path/to/your/extension/

Most modern IDEs (VS Code, PhpStorm) let you do the same search across all files instantly. Look for any identifier starting with a capital J followed by a capital letter — that's almost always an old Joomla class name.

2. Enable Joomla's Deprecation Log

Joomla has a built-in tool for catching deprecated code at runtime:

  • Go to System → Global Configuration → System
  • Set Debug System to Yes
  • Set Log Deprecated API to Yes

Then browse your extension's pages. Joomla will log every deprecated call to a file in /logs/deprecated.php. This catches runtime deprecations your static search might miss.

3. Prioritize What to Fix

Not everything needs to be fixed immediately. Prioritize in this order:

  1. JFactory and JHtml calls — these are confirmed removed in Joomla 7
  2. Old MVC class namesJModelList, JControllerLegacy, etc.
  3. jimport() calls — replaced by PSR-4 autoloading
  4. J-prefixed helper classes — JText, JRoute, JUri, etc.

Step-by-Step Migration Walkthrough

Let's walk through migrating a real-world component model from legacy to Joomla 7 compatible code.

Before — legacy code that breaks on Joomla 7:

<?php
defined('_JEXEC') or die;

use Joomla\CMS\MVC\Model\ListModel;

class MyExtensionModelArticles extends ListModel
{
    protected function getListQuery()
    {
        $db    = JFactory::getDbo();
        $user  = JFactory::getUser();
        $app   = JFactory::getApplication();

        $query = $db->getQuery(true);
        $query->select($db->quoteName(['id', 'title', 'created_by']))
              ->from($db->quoteName('#__myextension_articles'))
              ->where($db->quoteName('created_by') . ' = ' . (int) $user->id);

        return $query;
    }
}

After — Joomla 7 compatible with DI:

<?php
defined('_JEXEC') or die;

use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\Database\DatabaseInterface;

class MyExtensionModelArticles extends ListModel
{
    public function __construct(
        array $config,
        MVCFactoryInterface $factory,
        private CMSApplicationInterface $app,
        private DatabaseInterface $db
    ) {
        parent::__construct($config, $factory);
    }

    protected function getListQuery()
    {
        $user  = $this->app->getIdentity();

        $query = $this->db->getQuery(true);
        $query->select($this->db->quoteName(['id', 'title', 'created_by']))
              ->from($this->db->quoteName('#__myextension_articles'))
              ->where($this->db->quoteName('created_by') . ' = ' . (int) $user->id);

        return $query;
    }
}

The key changes:

  • Database and application are injected via constructor — no static calls
  • All references use $this->db and $this->app — explicit and testable
  • No JFactory, no hidden global state
  • The class now clearly declares what it needs

When Will Joomla 7 Be Released? How Much Time Do You Have?

No official release date has been announced — Joomla's development is community-driven, and timelines depend on contributor availability and the scope of remaining work. However, the signal is clear: the 7.0-dev branch is active right now, and the June 6 sprint removed over 100 deprecations in a single day.

More cleanup sprints are planned. Each one removes more deprecated code. The gap between "this works" and "this breaks" is narrowing with every sprint.

The practical answer: you have time, but not unlimited time. Extension developers who start now can migrate methodically, test thoroughly, and ship updates before Joomla 7 lands. Those who wait will face a scramble. Your users on early Joomla 7 adopter sites will find broken extensions — and they won't wait patiently for fixes.

Start with your most-used extensions. Run the deprecation log. Fix the JFactory calls first. It's less work than it looks once you get into a rhythm.


Conclusion: JFactory Served Joomla Well — Now It's Time to Move On

JFactory was a practical solution for its era. It made Joomla accessible to thousands of developers and powered millions of extensions and sites. But software that doesn't evolve becomes a liability — and JFactory's time has come.

Joomla 7 is the clean break the project needs. A codebase without legacy static helpers is faster to learn, easier to test, and more aligned with the modern PHP ecosystem. The migration investment you make today pays off in every extension you build going forward.

The cheatsheet in this article covers the most common deprecated patterns. The DI container approach is the correct long-term direction. And the audit process gives you a clear starting point regardless of how large or complex your extension is.

Audit your extensions, run the deprecation log, and start migrating — one class at a time. Stay tuned to thepixel.dev for more Joomla 7 guides, including our upcoming complete list of breaking changes and a step-by-step dev environment setup tutorial.

Already running Joomla 6? Read our previous article: Joomla 7 Is Coming: What Developers Need to Know Right Now for the full picture of what's changing in the next major release.