Caching in TYPO3—Part 1

Cache Me if you Can – Einblicke in Frontend-Caches in TYPO3

|Benni Mack

TYPO3 is known for its powerful and flexible caching mechanism. Understanding the basic concepts allows you to build faster websites that drive customer retention—visitors quickly go elsewhere if you make them wait.

Our TYPO3 caching blog series is ideal for developers familiar with TYPO3 who want to fully understand the core concepts and build robust and faster websites with TYPO3.

What is a Cache?

Caching is a technique whereby a calculation or query is executed once, then stored for future reference. This can make all subsequent queries much faster.

One problem with this approach is that the cached version can become out of date if information, such as a database entry, changes. For this reason, the cached data needs to be invalidated periodically or whenever the source information changes.

The cached data also needs to be identified by certain parameters so it can be retrieved when appropriate.

Caching in the TYPO3 Frontend

TYPO3 has included resilient caching mechanisms for over a decade now. These have proven to be robust and flexible. At the time of writing, we’re looking at TYPO3 v10 specifically, although all concepts already existed in a similar fashion in previous versions of TYPO3. 

There are a number of different caches within TYPO3. In this article we’re focusing on the cache mechanism for generating and rendering a single page.
When TYPO3 renders a specific page on a website, it fetches the output—typically HTML—from TYPO3’s internal caching framework. TYPO3 offers granular caching configuration options. By default, a webpage rendered with TYPO3 is stored for 24 hours in the TYPO3 cache. This cache entry contains data based on all the content and plugins on a page, but also takes into account all relevant URL query string parameters (more on that later) as well as the currently logged in user and their user group. This means TYPO3 caches the output on a per-user-group basis so that, for example, a menu entry that is only accessible to logged-in users can still be retrieved from the cache.

Uncacheable Blocks

Certain parts of a page might have a piece of specific information, like a personalized greeting, like “Good Evening Benni,” which should never be cached. At b13, we call these parts of a page “uncacheable blocks”. TYPO3 refers to them as “USER_INT” or “COA_INT” objects. TYPO3’s caching mechanism puts placeholders in the cached data as HTML comments–just like the Edge-Side-Includes or Server-Side-Includes approaches and replaces them at the end of every single request with fully dynamic content.

If there are no uncacheable blocks on a website, and the visitor is not logged in, the page is “fully cacheable.” Then, TYPO3 can fetch the full HTML output directly from the cache with a single query to the cache.

Dangerous flag “no_cache”

It is possible to disable storing anything in, or retrieving anything from, the TYPO3 cache by using the infamous “no_cache” parameter. This option can be used by calling a URL like https://b13.com/about-us?no_cache=1. Site administrators can also set this via TypoScript. In previous versions, this flag could even be set on a per-page level. However, we consider this option highly dangerous. When using no_cache=1, TYPO3 does not attempt to store or retrieve anything from the cache. It renders everything for every individual request, making the web server vulnerable to denial-of-service (DoS) attacks, as each request takes more CPU time than necessary to render.

To address this, the no_cache parameter can be disabled system-wide in the “Admin Tools” => “Settings” area by activating the flag “disableNoCacheParameter” within the “Configure Installation-Wide Options” list.

Looking at the Cache when Visiting a Page

When we are consulted to analyze and improve TYPO3’s performance for a website, we look at the website from three angles:

1. Visiting a page for the first time (“cache miss”)–we call it “first hit”

In this scenario, all of TYPO3’s instructions are fetched, all content and all menus are generated, links to other pages are resolved, permission checks are carried out and all referenced images are validated and resized. Once the final output is computed, we have one large string.

The result is stored in the “pages” cache. If there are uncacheable blocks, this information is stored in the cache as well, as these parts need to be executed later on for each request.

The final output (HTML, JSON or RSS) is then sent to the browser.

Note:

There are various other caches (such as the “core cache” and the “labels cache”) which we will have a look at in a later chapter. Those can affect the rendering time of a “first hit” as well if they haven’t been properly warmed up.

2. Visiting a page with a valid cache entry–“cached hit”

The contents of a page—menu items, text, media, etc.—have all been calculated cached on a previous hit to the page and are fetched directly from the cache. Calling a cached page is usually approximately 10 times faster than the first hit. So you’ll notice a major loading difference between a first hit and a cached hit.

2a) No uncacheable objects and no user groups–“Fully Cached Page”

If there are no uncacheable blocks and no user is logged in, the page could even be cached by a proxy or CDN, resulting in a delivery time of around 20-40ms. By activating the TypoScript option “config.sendCacheHeaders”, you tell TYPO3 to send the appropriate HTTP headers to the browser to the page for a certain amount of time within the browser cache.

2b) A page with uncacheable objects

A lot of plugins use the uncacheable block mechanism (USER_INT). Login forms, or areas indicating whether a user is logged in, are common use cases. 

However, some extension authors sometimes do not fully validate whether a plugin is cacheable. Even if the plugin shows “nearly real-time” information, the plugin could be configured to only be cached for 1 hour, 30 minutes or even 1 minute.

Note:

When an editor or administrator is logged into the TYPO3 backend, a cookie called “be_typo_user” is set, which allows editors to preview hidden pages. When logged into the TYPO3 backend, a page is never fetched from or put into the cache, so you should always measure rendering time in a separate browser or private browser tab where you are not logged into the backend.

On the other hand, an element like the login form that, for example, indicates the current login status in the header area of every page of a website, should never be stored in the cache. Here’s a great tip: Fetching this part with an AJAX call makes the rest of the page fully cacheable. In fact, TYPO3’s community hub—TYPO3.org—does exactly that. However, this also means that every visit to a page triggers two calls to your TYPO3 application.

Keeping this information in the back of your head and doing comparisons in the network tab of a browser already gives you a good indication of where a possible bottleneck of a TYPO3 webpage may be hiding.

Every TYPO3 Project is Different–and has Different Requirements

TYPO3 ships with reasonable default caching settings for regular websites so that many users do not have to configure anything when building a website. However, they are not optimized to every possible use case, which can range from purely static to highly dynamic websites. Depending on one of the angles discussed above (see sections 1, 2, 2a and 2b), TYPO3 already automatically sends the HTTP response headers relevant for browsers and cache servers using the previously described TypoScript setting. However, extensions can modify these headers and site administrators can configure them as well. So in order to fully understand the system’s performance, one must carefully analyze how and why these parameters are sent.

As soon as an editor modifies content on a page, or changes the page title, the page and all pages pointing to this page need to have their cache entries invalidated. TYPO3 does this automatically for you under the hood.

The cached hit needs to be as fast as possible. Depending on the project it should not take longer than 100-200ms.

Analyzing the first hit (preferably with the help of profiling tools like Blackfire can make it more likely to spot a possible bottleneck, revealing some insights on what takes a lot of computing time. So-called mega menus, or separate mobile menus on the same page for various browser breakpoints, create an unusually large number of links (and HTML code) on a page, making the uncached first hit very slow. 

Editors should never need to clear any cache manually if the developer has utilized TYPO3’s full caching power.

Below, we show you a few tricks that we use for all of our projects.

Optimizing TYPO3’s Caches

Choose the right cache backend

By default, TYPO3 stores cached information in the database (in tables like “cache_pages” or “cache_rootline”). But using the database as a cache can result in slow page rendering. Often the database is stored on a different server, leading to increased network latency, which will add to the system’s overall response time. Having the database service running on the same server can result in the database taking up lots of CPU resources. A relational database such as MySQL is not the ideal tool to use for caching, but all hosters offer a database suitable for TYPO3, so this option is always available.

In more advanced setups, TYPO3 can be customized to use a different cache backend. We’ll highlight the different caches backends in a further chapter.

A cache backend is like an adapter that tells the system where the cached information should be stored. TYPO3 offers adapters for databases, filesystems, pure memory stores, and distributed backends out-of-the-box. As a rule of thumb, putting the most pressing caches for frontend output into a memory-based cache like Redis or Memcached makes our websites load 30% faster. These include “pages” for cacheable page output, “pagesection” for TypoScript instructions and “rootline” for hierarchy-based information of pages, all of which are the “frontend caches” an editor can clear in the TYPO3 backend). Because of the speed improvement, we ship all of our TYPO3 projects hosted in our TYPO3 supported environment with a configured Redis service by default. A fully cached page in TYPO3 configured with Redis as cache backend only needs one database request. The database can then be used solely (and therefore more efficiently) for content management and data retrieval.

Using the right cache backend is crucial, but also highly dependent on your hosting infrastructure. If your database server is located on a remote server, but no memory cache is available, it might be feasible to store your caches on the filesystem—if the server runs with a fast SSD hard disk. But: Using a file-based cache backend is highly discouraged for distributed systems sharing files via NFS. So in general, there is no best way for everybody out there—but there is a specific best way for your project!

Before considering running TYPO3 in a multi-node server setup for performance reasons, ensure you understand the actual bottlenecks of your system and optimize the underlying code or configuration.

We highly recommend reaching out to your hoster and asking about Redis or Memcache support for your TYPO3 website.

Verify your frontend output and adapt the cache lifetime

If you have a small TYPO3 website and your typical content doesn’t change on a daily basis, your site administrator can set the TypoScript option config.cache_period to 30 days or more. This determines the longest period that can elapse before the browser checks the server for a new version of the content. If a particular page, like your news page, needs a lower caching lifetime, you can modify this in the page settings.

And don’t forget

If you modify page content, your caches for this page get invalidated automatically.

Make sure caching isn’t accidentally turned off

Scan for any “no_cache” flags in your TypoScript configuration, and try to find out why this option was set in the first place. We’ve heard about slow TYPO3 setups where developers turned on this option for development purposes but forgot to remove that setting before the page went into production.

Are you sure that object is uncacheable?

TYPO3’s Admin Panel (comes with the system extension adminpanel) can be used to identify uncacheable objects on your webpage and verify if those really need to be uncacheable.

Trigger first hits with the crawler extension

When your “first hit” is slow and you know you can’t do anything about it—perhaps due to various user group combinations and logged-in states, there are ways to warm up these pages periodically by using the crawler extension or a custom warmup extension.

Use a reverse proxy or CDN

The webserver and the PHP version in use could also become bottlenecks when considering a more performant website, where more optimizations can be achieved in a reasonable amount of time. An audit via web.dev can identify if there are pieces other than TYPO3 that could make your website load faster.

We use web.dev and Blackfire to optimize performance rendering times on our setup to ensure that we get the most out of TYPO3. Feel free to reach out to us and consult b13 to make your visitors’ experience a pleasure.

Once you’ve optimized your PHP execution times, and you still want to improve the rendering times of a fully cached page, consider using a proxy like Varnish, or a CDN. This needs some developer experience, but we believe these optimizations are worth the effort. At b13, we use Cloudflare as a CDN provider. Cloudflare offers a global scope for having fully cached content available, and even more features like a Web Application Firewall, so your server setups need even less CPU power, since most requests are already handled by the CDN. But beware: With more caching come more pitfalls with regards to not invalidating cache entries properly.

Benefits of a cacheable webpage

Our core business at b13 is delivering highly customizable, multilingual websites with global reach. Performant websites are a must-have for today’s globally active businesses. Talking to SEO agencies and search index maintainers shows us that performance is the key benefit not just for search rankings, but actually to make the users feel happy on your website.

TYPO3 supports us delivering just that when we follow its internal-caching best practices.

So what can you do?

  • Ensure that you’ve fully optimized your website following the steps above. If you still feel like there is room for improvement with your existing TYPO3 website, ask us for an independent audit of your project.
  • Make sure that the webserver setup is not the actual bottleneck, and optimize for performance beyond PHP.

Our next blog posts in our caching series will give you more insights into the infamous “cHash” parameter, and later-on we’ll also show you how your editors will never ever have to clear a cache ever again because you will have everything perfectly optimized!

See more about cHash-Parameters in Part 2 now.