
Joomla Performance: A Practical Guide to a Faster Website
A slow website loses visitors before it ever shows them anything. Half of them leave while the page is still loading, search engines rank the site lower, and every campaign you run pays for clicks that bounce. The good news: most slow Joomla sites are slow for reasons that are cheap to find and fix - and Joomla ships more performance tooling than most people ever switch on.
This article explains Joomla performance optimization from top to bottom. It covers the basics and quick wins for owners, measurement, images, assets, and server tuning for administrators, and profiling and query discipline for developers. It builds on the Focus On article about Joomla cache, which covers the caching system in depth; here caching is one chapter in the bigger story: measuring, the server stack, images, CSS and JavaScript, extensions, the database, and CDNs.
Performance is not one big switch. It is twenty small ones, and knowing which ones matter for your site.
The goal is simple: help you make your Joomla site measurably faster, in the order that gives the biggest wins first.
1. The Basics
1.1 Why Speed Matters
- Visitors: every second of load time costs conversions and patience; mobile visitors on slow networks feel it double.
- Search: Google uses page experience signals, measured through the Core Web Vitals, as a ranking factor.
- Money: a faster site does more with the same hosting, and ads pointing at a slow site burn budget.
1.2 The Four Layers of Joomla Performance
| Layer | Examples | Typical share of the problem |
|---|---|---|
| Server | PHP version, OPcache, database, hosting quality. | The foundation everything sits on. |
| Joomla | Caching, gzip, session handling, extension count. | The switches this article covers. |
| Frontend | Images, CSS, JavaScript, fonts, template weight. | Usually the largest share by far. |
| Network | HTTPS setup, compression, CDN, distance to visitors. | Matters most for international audiences. |
The frontend layer deserves emphasis: on most sites, the bytes that dominate load time are images and scripts, not PHP. Tuning the server while shipping 4 MB hero images is polishing the engine of a car with square wheels.
1.3 The One Rule: Measure First
Never optimize blind. Measure, change one thing, measure again. Without numbers you cannot tell a real improvement from a placebo - and performance work is full of placebos.
Back to top2. Measuring: Know Before You Tune
2.1 The Core Web Vitals
Google's Core Web Vitals are three user-centric numbers, measured on real visits:
| Metric | Measures | Good |
|---|---|---|
| LCP (Largest Contentful Paint) | How fast the main content appears. | <= 2.5 s |
| INP (Interaction to Next Paint) | How fast the page reacts to clicks and typing. | <= 200 ms |
| CLS (Cumulative Layout Shift) | How much the layout jumps around while loading. | <= 0.1 |
Test with PageSpeed Insights (lab data plus real-user data when available) and Lighthouse in the browser's developer tools. Test the pages that matter - the home page, a typical article, the busiest landing page - on mobile settings, because that is where the thresholds bite.
Next to the three vitals, watch TTFB (Time To First Byte): the raw server response time. It is the number that Joomla caching, PHP versions, and hosting quality move directly. A slow TTFB points at the back half of this article; a fast TTFB with a slow LCP points at the frontend.
Lab tools measure one page at a time. Professional crawlers such as Screaming Frog (free up to 500 URLs per crawl) extend the measurement to the whole site: every oversized image, every redirect chain, every heavy page - and, with the paid PageSpeed Insights integration, Core Web Vitals for the full site in one report. For anything beyond a handful of page types, one crawl replaces hours of page-by-page testing.
2.2 Joomla's Own Measuring Tool
For the PHP side, Joomla's Debug System (Global Configuration → System, plus the System - Debug plugin) shows exactly where time goes: every database query with its duration, memory usage, and profiling marks through the request. Ten seconds of reading the query list finds the module that fires two hundred queries. Use it on a development copy - debug stays off in production, as the security hardening article insists.
2.3 Keep a Log
Write down the numbers before and after every change: date, page, LCP, total weight, requests. It keeps you honest, shows which changes actually mattered, and gives you a baseline when someone says "the site feels slow lately".
Back to top3. The Server Foundation
3.1 PHP Version and OPcache
Each major PHP release is measurably faster than the last, so running a current PHP version is free performance (and free security, as the hardening article notes). Just as important: OPcache must be enabled. It keeps compiled PHP bytecode in memory so Joomla's code is not recompiled on every request - on most hosts it is on by default, but verify it in your hosting panel or a phpinfo output on a dev copy.
3.2 The Database
Run a current MariaDB or MySQL, and give it memory to work with (the InnoDB buffer pool). On shared hosting you control little here, which is one more reason hosting choice is a performance decision: ask hosts about PHP versions, OPcache, database tuning, and SSD storage before you sign.
3.3 HTTP/2 and Modern TLS
HTTP/2 (or HTTP/3) lets browsers fetch many assets over one connection, which especially helps pages with many CSS/JS/image files. It comes free with any decent hosting stack over HTTPS - confirm it once with an online checker. If your host still serves HTTP/1.1 in 2026, that says something about the rest of their stack too.
Back to top4. Joomla Settings That Matter
4.1 Gzip Page Compression
Global Configuration → Server → Gzip Page Compression (gzip): Joomla compresses its HTML output before sending it. HTML compresses extremely well - typically to a quarter of its size - so this is a free win unless your server already compresses at the web-server level (then leave it to the server). Where the server offers Brotli, prefer it over gzip - it compresses better - and keep the rule from section 14.5: each response compressed exactly once.
On LiteSpeed and OpenLiteSpeed this is settled for you. Compression is a server switch (Server Configuration → Tuning → Enable Compression), it is on by default, and it covers dynamic PHP output with Brotli as well as gzip - OpenLiteSpeed ships a dynamic Brotli level of 2 out of the box. Leave Joomla's gzip off there. LiteSpeed does not re-compress a response that already carries Content-Encoding, so switching gzip on in Joomla costs PHP time and downgrades your visitors from Brotli to gzip. Check what actually arrives:
curl -sI -H 'Accept-Encoding: br,gzip' \
https://example.com/ | grep -i content-encoding
On a healthy LiteSpeed that answers br.
4.2 Caching On
Caching is the single biggest Joomla-level switch: Conservative caching in the Global Configuration plus the Page Cache plugin for guest visitors can cut server response times from hundreds of milliseconds to a few. The Focus On article about Joomla cache covers the levels, handlers (including Redis and Memcached for busy sites), and the pitfalls with logged-in users - read it as the companion to this section rather than having it repeated here.
4.3 Sessions
The default database session handler is fine for most sites. High-traffic sites write session data on every request, and moving sessions to Redis (where hosting offers it) takes that load off the database. Keep the Task - Session GC scheduler plugin active so expired sessions are actually cleaned up.
4.4 Switch Off What You Do Not Use
Debug System off in production (it adds work to every request), unused plugins disabled, statistics modules you never read unpublished. Every enabled extension runs code; section 7 makes this systematic.
Back to top5. Images: the Heaviest Part of Almost Every Page
5.1 Right Size, Right Format
The most common performance bug in the wild is a 4000-pixel photo squeezed into a 400-pixel column. Two rules fix most image problems:
- Resize to the displayed size before or during upload. Joomla's Media Manager includes core media action plugins - crop, resize, rotate - so editors can fix dimensions without leaving the backend.
- Use modern formats: the Media Manager accepts
webpandavifout of the box, and both are dramatically smaller than JPEG/PNG at the same visual quality. Converting is the one step Joomla core does not do for you - use an image tool or an extension for bulk conversion.
5.2 Lazy Loading
Browsers natively defer offscreen images when the loading="lazy" attribute is present. Joomla core does not add it to article intro and full images automatically - which makes this a perfect template override: add loading="lazy" (plus width and height) to the image markup in your override of the article layouts, and every article image below the fold stops competing with the visible content. Keep the attribute off the LCP image (the big visible one at the top) - lazy-loading that one makes the page slower.
5.3 Dimensions Against Layout Shift
CLS - the jumping layout - is usually images without dimensions. Always provide width and height (or CSS aspect-ratio) so the browser reserves the space before the image arrives. The Media Manager fills the fields for you when inserting images in the editor; overrides should preserve them.
6. Assets: CSS, JavaScript, and the Web Asset Manager
6.1 The Web Asset Manager Does the Bookkeeping
Joomla's Web Asset Manager loads CSS and JavaScript through named assets with dependencies and weights (the Cassiopeia article walks through a real joomla.asset.json). For performance it matters because assets load once, in the right order, deduplicated - and because script assets can declare attributes such as defer, so JavaScript stops blocking rendering. When you add your own assets, register them properly instead of pasting script tags into templates.
6.2 Load Assets Only Where They Are Used
The cheapest kilobytes are the ones you never send. Slider scripts, gallery CSS, map libraries: they belong only on the pages that show them, not in the global template. The Web Asset Manager makes this natural - register the asset once, then call useScript()/useStyle() in the module layout or override that actually renders the feature, and Joomla loads it on exactly those pages, deduplicated when several blocks ask for the same asset. Auditing a template for globally loaded one-page assets is often worth hundreds of kilobytes on every other page.
6.3 Precompressed Assets - Already on Your Server
Few people know that Joomla ships its core CSS and JavaScript precompressed: next to template.min.css sits template.min.css.gz. The shipped htaccess.txt contains a ready-made (commented) block that serves those .gz files directly to browsers that accept gzip - saving both bytes and on-the-fly compression work. If your server does not already compress assets, enable that block: it is free speed sitting idle on the disk. One exception: on LiteSpeed and OpenLiteSpeed the block does nothing. Those servers read rewrite rules from .htaccess but ignore mod_deflate directives such as AddOutputFilterByType - compression exists only as their own gzip and Brotli settings, and they keep a compressed copy of static files in their own cache anyway.
6.4 Fonts and Third Parties
Every external domain costs a connection before the first byte arrives. Cassiopeia's approach - fonts and libraries hosted locally, no CDN calls - is the right default for performance and privacy alike. Three font rules pay for themselves: limit the site to one or two families in the weights you really use, declare font-display: swap so text renders immediately with a fallback font, and preload the one font file your headlines depend on. Audit your third parties: each analytics snippet, chat widget, and social embed ships JavaScript that competes with your content. Keep the ones that earn their cost; drop the rest.
6.5 Template Weight
Template frameworks and page builders trade convenience for weight: multiple CSS frameworks, jQuery plus modern scripts, icon fonts for three icons. You do not have to rebuild the site to improve this - but when choosing a template for a new project, view the source of its demo and count the requests. Lean templates exist, and Cassiopeia with a child template is one of them.
Back to top7. Extensions, Modules, and Query Discipline
7.1 Every Extension Runs Code
Plugins run on events - some on every request. Modules run queries to build their output. A site with sixty enabled extensions carries the cost of sixty codebases on every page view. The audit is the same as in the security hardening article, with the same conclusion: uninstall what you do not use, and prefer one good extension over three overlapping ones.
7.2 Finding the Expensive One
With Debug System on (development copy), read the query list per page: it names the module or component behind each query. The usual suspects are "related items" and "latest news" modules with deep category trees, badly cached menus, and search modules counting things on every load. Most modules have their own cache setting in Advanced options - use it, as the cache article explains.
7.3 Content Discipline
Performance also lives in editorial habits: a homepage that embeds forty full articles instead of intros, category blogs listing hundreds of items without pagination, or a menu tree six levels deep all generate work per request. Structure content so a page shows what a visitor needs and links to the rest.
Back to top8. Database and Housekeeping
8.1 Scheduled Cleanup
The Task Scheduler earns its keep for performance too:
| Task plugin | Performance value |
|---|---|
sessiongc |
Clears expired sessions so #__session stays small. |
deleteactionlogs |
Prunes the user actions log before it grows to millions of rows. |
checkfiles |
Flags oversized files - the 40 MB PDF someone uploaded to the images folder. |
globalcheckin |
Frees stale locks that make editors reload and retry. |
8.2 Tables That Quietly Grow
A few tables grow with use and deserve an occasional look: the action logs, Smart Search's index tables (rebuild the index after large content changes), and any logging tables of third-party extensions. The database maintenance in System → Database keeps the schema in shape after updates; your database tool shows which tables actually hold the megabytes.
8.3 Version History Limits
Joomla stores content version history per item; the History Limit in each component's options caps how many versions are kept. The default is sensible - just do not set it to something enormous on a site with thousands of articles.
Back to top9. CDNs and Reverse Proxies
9.1 What a CDN Actually Buys You
A content delivery network caches your static files (and optionally whole pages) on servers near your visitors. For a Dutch site with Dutch visitors on decent hosting, the gain is modest. For international audiences, or as a shield in front of modest hosting, it is substantial: assets arrive from 30 km away instead of 3000, and traffic spikes hit the CDN instead of your server.
9.2 The Practical Route
The common setup is a proxy CDN (Cloudflare and similar): DNS points at the CDN, which caches static assets automatically and forwards page requests to Joomla. It combines naturally with the WAF role from the security hardening article - one service, two jobs. Joomla needs no special configuration for this; set behind_loadbalancer in the Global Configuration so Joomla sees real visitor IPs, and purge the CDN cache when you deploy big changes.
9.3 Keep the Origin Honest
A CDN hides origin slowness for anonymous visitors and static files - not for logged-in users, forms, checkouts, or the backend. Tune Joomla first, then add the CDN as the outer layer, not as a bandage over an untuned site.
Back to top10. Real-World Performance Recipes
10.1 The One-Afternoon Tune-up (Any Site)
- Measure the three key pages in PageSpeed Insights; save the numbers.
- Update Joomla, extensions, and PHP to current versions.
- Switch on gzip, conservative caching, and the Page Cache plugin (guests-only sites).
- Enable the precompressed-assets block in
.htaccess. - Fix the five heaviest images (resize, convert to WebP).
- Measure again and file the before/after.
10.2 The Image-Heavy Blog
Add loading="lazy" plus dimensions via article layout overrides, batch-convert the image library to WebP, and let the checkfiles task flag future oversized uploads. Largest Contentful Paint usually halves.
10.3 The Community Site with Logged-in Users
Page caching barely applies (see the cache article), so shift the effort: Redis for sessions and cache, module caching where content allows it, query discipline in the busiest modules, and a CDN for the static assets that are identical for everyone.
10.4 The International Brochure Site
Modest content, visitors everywhere: proxy CDN with full-page caching for guests, long browser-cache lifetimes for assets, and locally hosted fonts. The origin server barely works anymore.
Back to top11. Under the Hood (Developer View)
11.1 Reading the Profiler
With JDEBUG on, the debug bar shows profiling marks (afterLoad, afterDispatch, afterRender) with times and memory - telling you whether time disappears in bootstrapping, the component, or rendering - plus every query with duplicates flagged. That distinction decides where to optimize: slow dispatch means component/model work; slow render often means template or module work.
11.2 The Classic Slow Patterns
- Queries in loops: loading items one by one instead of one query with
whereIn(). The query list makes this visible instantly - fifty near-identical queries in a row. - Business logic in overrides: as the overrides article warns, an override that calls models runs invisible queries on every render.
- Uncached expensive work in modules and plugins: wrap it in the caching API (see the cache article) with a sensible lifetime.
- Events doing heavy work on every request: a plugin subscribed to
onAfterInitialisepays its cost on every single page view - keep those handlers trivial.
11.3 Ship Performance-Friendly Extensions
Register assets through the Web Asset Manager with defer where possible, declare dependencies instead of bundling your own copy of a library Joomla already ships, make your queries pagination-aware, and give your modules a cache option. Extensions built this way are the ones that survive the audits from section 7.
12. Performance and the Web Services API
API responses skip the whole frontend layer - no template, no modules, no assets - so they are naturally light; the cost that remains is the model and the database. The page cache does not apply to API requests, so heavy API consumers need their own strategy: request only needed fields, paginate honestly, and cache responses on the consuming side with normal HTTP caching semantics.
If you run integrations that poll the API frequently, watch them in the server logs: a well-meaning script fetching a full article list every minute can generate more database load than all human visitors together. Give integrations dedicated accounts (as the ACL article recommends) so their traffic is identifiable, and agree on sensible polling intervals or webhooks-style triggers via the Task Scheduler instead.
Back to top13. SEO and Metadata
Performance is one of the few technical topics where the SEO benefit is official: Google confirms page experience, measured through the Core Web Vitals, as a ranking signal, and real-user measurements of your actual visitors feed it. The practical implication: lab scores are diagnostics, but the field data in Search Console's Core Web Vitals report is the number that matters - check it monthly.
Speed also shapes crawling: search engines allocate a crawl budget per site, and a server that answers in 200 ms gets more pages crawled per day than one that answers in 2 seconds. On large sites, faster responses translate directly into fresher indexing. And every redirect chain, broken image, and timeout wastes crawl budget the same way it wastes visitor patience - the redirects article and this one solve the same problem from two sides.
Back to top14. Common Mistakes and Pitfalls
14.1 Optimizing Without Measuring
Symptom: weeks of tuning, no measurable difference - or a site that got slower.
Fix: baseline first (section 2), one change at a time, measure after each. Delete the changes that did not move the numbers; complexity without benefit is pure risk.
14.2 The 4 MB Hero Image
Symptom: a beautiful homepage with an LCP of eight seconds on mobile.
Fix: resize to the display size, convert to WebP, and never lazy-load the LCP image itself. This one fix beats every server tweak combined on most sites.
14.3 Debug Mode in Production
Symptom: every page carries profiling overhead, and the footer leaks query details to visitors.
Fix: Debug System off in production, always. Profile on a copy.
14.4 Caching as a Bandage
Symptom: the cached page is fast, but every cache miss (and every logged-in user) waits three seconds.
Fix: caching multiplies a fast site; it masks a slow one. Fix the underlying query and asset problems first, then cache the result.
14.5 Double Compression Confusion
Symptom: gzip enabled in Joomla and the server, or the precompressed-assets block enabled while the server already compresses - occasionally producing garbled output or wasted CPU.
Fix: compress each response exactly once. Check response headers (Content-Encoding); if the server already handles it, leave Joomla's gzip off and skip the htaccess block. On LiteSpeed and OpenLiteSpeed the symptom is quieter and the cost is real: the server accepts the gzip PHP already produced instead of applying its own Brotli, so the page stays correct but arrives bigger than it needed to be.
14.6 The Third-Party Script Collection
Symptom: analytics, tag manager, two chat widgets, social embeds - and an INP that fails on every phone.
Fix: inventory every external script, measure its cost in the performance tab, and keep only what demonstrably earns money or insight. Load what remains deferred.
Back to top15. Best Practices
If you remember only a few things from this article, remember these:
- Measure before and after every change; Core Web Vitals on mobile are the scoreboard.
- Fix images first: right size, WebP/AVIF, lazy-load below the fold, dimensions always.
- Run current PHP with OPcache, on hosting you chose with performance questions in hand.
- Switch on gzip, conservative caching, and the Page Cache plugin where the site allows it - and read the cache article for the details.
- Serve the precompressed assets Joomla already ships, via the htaccess block.
- Audit extensions and third-party scripts yearly; uninstall, do not just disable.
- Let the Task Scheduler do the housekeeping: sessions, logs, oversized files.
- Add a CDN as the outer layer for international audiences - after the origin is tuned, not instead of it.
- Developers: read the profiler, keep queries out of loops and overrides, register assets with defer.
16. Quick Reference
MEASURE PageSpeed Insights / Lighthouse, mobile, 3 key pages
CWV targets: LCP <= 2.5s INP <= 200ms CLS <= 0.1
TTFB = raw server response (caching/hosting territory)
Joomla: Debug System query list (dev copy only)
SERVER current PHP + OPcache on, current MariaDB/MySQL
HTTP/2 or HTTP/3 over HTTPS
JOOMLA gzip On (unless server compresses)
caching Conservative + Page Cache plugin (guests)
sessions: database ok, Redis for busy sites
debug Off in production
IMAGES resize to display size (media actions: crop/resize)
webp / avif accepted by Media Manager
loading="lazy" below the fold (via override, not core)
never lazy-load the LCP image; always width+height
ASSETS Web Asset Manager: dependencies + defer
page-specific assets: useScript()/useStyle() where used
enable the .gz precompressed block in .htaccess
fonts local, 1-2 families, font-display: swap
audit third-party scripts; Brotli > gzip where offered
HOUSEKEEP scheduler: sessiongc, deleteactionlogs, checkfiles,
globalcheckin; watch action log + finder tables
CDN proxy CDN for international reach + spike shielding
behind_loadbalancer On; purge on deploys
tune origin first
DEV profiler marks: dispatch slow = model, render slow =
template/modules; no queries in loops or overrides
module cache option; whereIn() over per-item queries
ORDER images > caching+gzip > extensions > server > CDN
Back to top17. Summary
Joomla performance work is a sequence, not a secret:
- Measure first: Core Web Vitals for the visitor experience, Joomla's debug query list for the PHP side.
- Foundation: current PHP with OPcache, a healthy database, HTTP/2 - hosting is a performance decision.
- Joomla switches: gzip, caching (the cache article is the deep dive), lean sessions, debug off.
- The frontend is the battlefield: right-sized modern-format images with lazy loading and dimensions, assets through the Web Asset Manager, the shipped precompressed files actually served, third parties audited.
- Discipline: fewer extensions, cached modules, scheduled housekeeping, honest content structure.
- The outer layer: a CDN for reach and resilience once the origin is fast.
None of this requires exotic tools - almost everything in this article ships with Joomla or with your hosting. What it requires is measuring, doing the boring fixes in the right order, and resisting the urge to buy a plugin before understanding the problem.
If your site fails its Core Web Vitals and you cannot tell why, a structured performance audit - measure, layer by layer, biggest cost first - usually finds that eighty percent of the slowness has two or three causes. Finding them methodically instead of guessing is exactly the kind of work a Joomla specialist does well, and the difference is measurable the same afternoon.
Back to top

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.












