whoami
Lucas Jenß
cat /etc/motd
The Coding Journal ツ — Notes taken on an epic coding journey. Technical solutions, debugging notes, and practical guides from the trenches of software development.
ls -la ~/languages/
- drwxr-xr-x
- ▶ PHP
- ▶ Ruby
- ▶ Scala
- ▶ C#
- ▶ JavaScript
- ▶ Objective-C
- ▶ Shell Scripting
ls -la ~/toolchain/
- drwxr-xr-x
- ▶ Typo3
- ▶ Akka
- ▶ Capistrano
- ▶ Git
- ▶ MAMP
- ▶ Adobe Illustrator
- ▶ NSTrackingArea (Cocoa)
uname -a
- drwxr-xr-x
- ▶ Mac OS X
- ▶ Unix
TYPO3 caching framework: clearing the frontend cache safely
TYPO3 powers many Australian editorial sites, from Sydney newsrooms to Melbourne e-commerce stores, and one of the most common developer tasks is clearing the cache. The TYPO3 caching framework separates frontend and backend storage so editors, schedulers, and visitors do not step on each other. A well-aimed cache flush can mean the difference between a five-second deploy and a fifteen-minute support call.
This post walks through how the framework is built, why a partial frontend flush usually beats a global one, and the code paths that target specific pages. I also touch on a few practical concerns unique to local hosting, like NBN latency between data centres and the way cron-driven automation interacts with editorial work.
The architecture behind the TYPO3 caching framework
The TYPO3 caching framework is a layered system built around the abstract CacheBackend interface. Two frontends, the VariableFrontend and the StringFrontend, give developers a consistent API to store serialised PHP values, while the actual storage is handled by interchangeable backends such as the DatabaseBackend, the FileBackend, the RedisBackend, and the MemcachedBackend.
TYPO3 splits caches into two families. Backend caches (system, runtime, configuration) live in var/cache/code and are normally flushed during a deploy or an extension update. Frontend caches hold the rendered HTML of pages, cObj fragments, and group identifiers, and they are what visitors receive.
A critical piece of that architecture is cache tags. When a page is rendered, TYPO3 attaches tags like pageId_42 or tx_news_pid_7 to the entry. The framework keeps a separate index of these tags, so it can locate and invalidate related entries without scanning the keyspace. A single news article update is reflected on the homepage, category overview, and search results without a single global flush.
When a full flush is the wrong choice
The Install Tool's "Clear all caches" button is a blunt instrument. It empties cache_core, cache_hash, cache_pages, and every other pool, then forces the next request to rebuild everything from scratch. On a small site that is harmless. On a Sydney news portal serving a million page views a day, the rebuild cost is paid by real users, and TTFB can spike from 80 ms to over two seconds.
Selective invalidation is the answer. If an editor in Brisbane changes a single news record, only the cache entries tagged with that record's page ID and storage PID need to go. Editors keep working in the backend without seeing the "Clear cache" button, and visitors see the updated headline within a single request.
The same logic applies to translations. Flushing the whole page cache means every other language is rebuilt as well, which is wasted CPU. A targeted flush respects the multilingual structure the framework already tracks. The kitchen parallel is hard to miss: clearing the whole fridge because one sprig of parsley has wilted is the same mistake, and a measured approach to keeping fresh herbs follows the same logic you want in a cache layer.
Clearing frontend cache with the API
The cleanest way to flush frontend entries programmatically is through the CacheService. Inject the service into your controller, fetch the frontend cache by identifier (usually cache_pages), and call flushByTags() with the tags that should disappear.
A minimal example:
$cacheService = GeneralUtility::makeInstance(CacheService::class);
$cacheService->flushByTags(['pageId_42']);
If you need to act on every page that belongs to a given storage PID, build the tag list before calling the flush:
$tags = ['tx_news_pid_7', 'pageId_7', 'pageId_8', 'pageId_9'];
$cacheService->flushByTags($tags);
For deployments, I run this from a Capistrano recipe that syncs uploads and shared folders across the staging cluster, then triggers a partial flush once the new release is live. The pattern from the sync uploaded files across servers post explains how to wire it up so the file system and the cache are handled together.
Cache tags, page IDs, and grouped invalidation
Cache groups pre-date tags, and they are still useful for invalidating a logical slice of the site. The page cache is registered with the group "pages", and you can flush that group with a single call:
$cacheService->flushGroup('pages');
Tags are finer-grained. A useful pattern is to listen to a DataHandler hook after a record has been saved, then derive the relevant tag list from the table and the page. The EXT:news extension uses this approach to keep the homepage in sync after an article is published.
I keep the hook lightweight in my own setups. I only flush by tags that I know are used by rendered content, and I avoid touching cache_hash or cache_pagesection unless something has actually changed. The fewer caches you touch, the less work the next request has to do.
Common tag sources in a typical project:
- Page ID tags, which the framework attaches to every rendered page
- Storage PID tags, which the DataHandler adds when content is saved
- Extension-specific tags, which an extension registers in ext_localconf.php
CLI tools and the typo3 cache:flush command
The CLI command vendor/bin/typo3 cache:flush accepts a --group argument that lets you target a specific group. For frontend-only work, the most useful invocation is:
vendor/bin/typo3 cache:flush --group pages
This is the command I run from a cron job on a Melbourne-hosted staging box every night, after a content import has finished. The cron entry lives in /etc/cron.d/typo3-staging and writes a small JSON log so I can confirm in the morning that only the page cache was touched.
If you also use the Symfony Messenger consumer to process background jobs, you can flush the message queue's spool and the page cache from the same script, which keeps runtime and persistent cache consistent. Doing both from a single worker avoids the race condition where a queued email tries to render a page that no longer exists in the cache.
Pitfalls when editors and cron jobs run together
The most common support ticket on Australian TYPO3 installations is a phantom "my change is not showing" issue. Nine times out of ten, it is a race between an editor saving a record in the backend and a scheduled job running cache:flush on the same second. The editor saves, the cron flushes everything, and the editor believes their save was ignored.
The fix is twofold. First, schedule your cron jobs to skip the working hours of the editorial team in AEST, or flush by tag rather than by group. Second, configure the backend's "clear cache" behaviour to honour the same tag list, so a manual click only wipes what the editor changed.
A related pitfall is the file backend on shared hosting. Some Australian hosting providers, including a few in the VentraIP and Panthur ecosystem, still default to the FileBackend for cache_pages because Redis is treated as an optional add-on. The file backend is fine for low-traffic sites, but on a shared inode budget it can become a bottleneck during a global flush. Switching to Redis is often cheaper than upgrading the hosting plan.
Performance realities for Australian sites
Caching strategy is shaped by the physical distance between visitor and origin. A Sydney-hosted site still serves Perth visitors with around 50-60 ms of one-way NBN latency, before any SSL handshake. A 250 ms TTFB feels slow in Melbourne and glacial in Perth, which is why most Australian agencies I work with keep cache TTLs aggressive and use Varnish or Redis in front of TYPO3.
Australian privacy law also plays a quiet role. The Privacy Act 1988 and the Australian Privacy Principles require that any user data written to a log or stored in a cache be handled according to the entity's APP obligations. If your caching layer logs IP addresses for analytics, that data falls under the Act, and a cache flush should not be confused with a data deletion. The ACMA's guidance on data retention is worth reading if you cache anything that could be personal information.
| Mechanism | Granularity | Typical use case | Risk if overused |
|---|---|---|---|
| flushByTags() | Per record / per page | Editor saves a single news article | Negligible if tags are correct |
| flushGroup('pages') | Per group | Nightly content import or schema change | Brief TTFB spike on large sites |
Full cache:flush |
Everything | Extension install, TYPO3 upgrade | Several seconds of warm-up time |
cache:flush --group system |
Backend only | Deploy of configuration files | Forces a recompile of the DI container |
Helpful habits when working with the cache:
- Keep a list of cache groups your project uses in a central configuration file
- Wrap every DataHandler hook in a try/catch and log the tags that were flushed
- Run
cache:flush --group pages --forceonly when you actually need to bypass the lock file - Verify the result in the frontend before assuming the flush worked
Speak with the team that owns your hosting in Australia before you change backends. Switching from FileBackend to RedisBackend on a Brisbane-hosted site is a thirty-minute job with zero downtime if the panel supports a managed Redis add-on, and it removes the inode pressure that so often causes a global flush to crawl. If you are moving between hosts, or refreshing the local emulator stack on a developer laptop, the hardware acceleration on Linux walkthrough is a useful companion read for keeping test environments consistent with staging.
When you are ready to roll the changes out, push the partial flush through the same deploy script that handles file syncs and database migrations, run a smoke test against the production domain, and only then promote the new release. Caching in TYPO3 rewards operators who treat it as a precision tool rather than a hammer, and a few minutes of care at deploy time pays off in smoother editor experience and faster page loads for visitors from Adelaide to Darwin.
cat ~/interests.json
| Key | Value |
|---|---|
| editor | Terminal-first workflow |
| os | Mac OS X / Unix |
| vcs | Git, distributed version control |
| deploy | Capistrano, cron automation |
| graphics | SVG, Adobe Illustrator troubleshooting |
| networking | IP validation, SSH, VPN |
git log --oneline --reverse
Solving SVG import issues in Adobe Illustrator CS6 and CC
When importing an SVG into Illustrator, the operation fails with an unknown error [CANT]. A workaround for this Adobe-side bug.
Solving NDK build issues on OS X
Troubleshooting native development kit compilation problems on Mac OS X.
Programmatically adding PHP generated TypoScript to the backend configuration
Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.
ArgumentError: Could not parse PKey: no start line
Debugging an SSH key parsing error encountered during deployment.
Validating IP-Addresses in PHP
Using PHP filter functions with flags like FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6, and understanding how filter_var handles reserved IP addresses.
Cocoa: Using NSTrackingArea
A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.
cat ~/contact.txt