Django Tasks - Jake Howard
Published April 15, 2026
This video features Jake Howard at Wagtail Space NL 2024 in Arnhem, Netherlands.
Wagtail Space NL 2024 https://nl.wagtail.space
Caching lets Wagtail reuse work it has already done, and can reduce both response times and server load—but it complements rather than replaces benchmarking and other performance work. Wagtail’s template fragment caching (introduced in Wagtail 5.2) can reuse rendered HTML for components such as listings and navigation; its page-aware cache tags account for site and preview context, and page cache keys allow published changes to invalidate fragments. A CDN can serve cached pages closer to users without sending every request to Wagtail, while Wagtail’s CDN integration can purge affected pages when content is published. The higher a cache sits in the stack, the more work it can avoid, though caching does not make an intrinsically slow page faster when a cache miss occurs.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Okay, so as was already mentioned, um I'm here to talk about caching in Wagtail, some ways you can dramatically improve the performance of your site, sometimes with actually very little effort. So a little bit about me. I'm Jake. I'm the same Jake that Tom said very nice things about. I'm a senior systems engineer at TorchBox. I'm also on the security team, the performance team, and as of two weeks ago, the core team for Wagtail. I do have other things I do at work, honest. And I exist in many places on the internet. Now, a bit of a disclaimer before I get started. This isn't a generic performance talk. Optimizing Python, Django, and even Wagtail are very much their own topics and very big topics. Caching is just a part of optimization, but it's not the only part.
And it's not a replacement for doing proper benchmarking and proper investigations. So what is caching? Caching is the idea of letting your code remember the things that it has already done. Reusing a value that you've already done. um the work for to calculate because it's generally it's always slower to do something than to do nothing. Now caching comes in many different forms. From storing variables outside of a loop to caching functions, to caching entire pages. Today I'm mostly going to be focusing on the higher end, so functions, pages, things like that. But the higher up that list you go, the more smaller processes you are caching, and the more performance you are able to get Now, caching may not wow that seems very ominous.
Um caching may not seem like something that you need at some scales. Smaller sites will probably work fine without it But as your site grows, it becomes more and more important. Otherwise you'll crash under your own weight and success. But that may not be something that you notice until it's already an issue. What runs fine locally may not in production. And that is a problem with so many things when it comes to running a scale. Um if a page gets so popular it will soon meet with the hug of death Um when it gets so overloaded by its own popularity that it fails to function. And even sometimes it's not just based on its popularity, sometimes it can just be shared around a bit. There was an issue with Mastodon, the Fediverse tooling, recently, where if you posted something on your own page, it would get picked up very, very quickly by anyone that follows you.
All at once and cause you massive issues. Caching is a nice way to help with that. Let's get the big words scale off of the page. There we go Now, back to Wagtail, because this is Wagtail space after all. I'm going to talk about two techniques to help you out with caching in your Wagtail site Both of these are included in maintained versions of Wagtails, you can start using them right now. Step one. Well, not step one. Item one. Template fragment caching. It's a lot of complex words, but it's actually quite a simple content c uh quite a simple content. Concept. There we go. This is introduced ish in uh Wagtail 5. 2. Now, most of what you build in Wagtail will come out as HTML, pages that are going to get shown by the browser.
But it probably takes a lot more intensive actions to actually create set HTML. You might have complex lists and filters and suggestions You might have finding and in fact rendering lots of image renditions. You might have rendering complicated stream-filled blocks or blocks in blocks in blocks, as we just heard about, etc. etc. etc. These can all be optimized in many, many different ways. The deeper down you go, the more complex and the less impactful sometimes those performance optimizations can be. And so you might be thinking, why can't we cache an entire chunk of HTML with all of that complexity contained within it? Rather than caching the name of a page in the navbar, why not cache the entire nav bar? That's the thing that people see
ish. So to give a bit of an example and a bit of subtle self-promotion, I'm going to use my own website. as an example. It is a relatively simple blog currently built with Wagtail. Now, here is a list of posts. Each item does have quite a lot to it. You've got a title, a date, an image with renditions or potentially pulled from Unsplash. You've got introduction text that is dynamically generated based on the full page the full content. You've got tags, you've got reading time and word count. All of these things come from various different places in the code base. They might be database fields, model properties, separate template tags, things like that. And as I said, it would be nice to cache all of these things together.
And that is what template fragment caching is, conveniently. So let's look at the template. I like to keep my templates nice and reusable and so this lives in its own separate file for that little listing item thing that we saw earlier. And it makes it very nice and easy to work with and it makes the caching conveniently much easier too. Now this template has absolutely no caching at all. Every time I use this template, the template is evaluated. All the template tags get run, all the database code gets executed, everything else. So let's add a cache to it. And in one very small step It should I'm gonna stop using the remote, it doesn't work. It should be cached.
Now there is caching. It's nice and simple. Realistically, it is just two lines of change. Now the tag itself, the main one at the top, Wagtel PageCache, which you can just about see on the screen, is where the magic happens. And it might look a little bit strange. It's not an inclusion tag, it's not a filter tag, it is a fully custom template tag. So let's look at its structure a little bit. We have the name, in this case, in fact there's a time to live, which tells me how long the cache should live for. We have the name to uniquely identify this fragment against a different fragment. In this case, listing item. And then we have whatever things after it that the cache needs to vary on. So in this case, I want if breadcrumbs are showing is an extra bit of configuration.
I've got if I'm showing images, again, a little bit of extra configuration. If I don't want to show images on a certain usage, then it gets a different entry in the cache. And then you put the actual HTML that you want to cache inside the middle. Now it is still a Django template, and so all those tags will get cooled completely fine, but nicely they will get cached too. So they only get run when the cache misses. Now, the template itself is in charge of caching itself. That keeps the complexity nice and hidden when I want to use the template. Um and the the pages using it don't need to cow or even know in some cases that the content inside it is being cached. Now, the listing item is a component and it's used in a few different places.
And you've got the posting list I showed earlier, but you've also got cert. and a few others. But the UI is identical in all of those places. And it takes the same context, a page, and it spits out some HTML. And it looks the same, it's just on different pay on different pages. So can I reuse it? Well it's in the cache? Yes, fundamentally. Um all I need to do is include that template tag somewhere else and the cache gets reused. So long as the right variables are available in context, it just picks it up and works with it. This works massively for improving shared components across your entire site. They can all be accelerated. And entire sections like the navbar can be cached once and reused dotted around your site.
Now, caching HTML blocks does have a few nice benefits that things like caching an entire page doesn't. For example, the search page. Searches are still performed live. When I type something in, it hits the database with every single page request. But the displaying of the results are not. So what that means is that I can do a circuit. I know, okay, there are four results. I know what those four results are, but I don't need to go through the work of calculating what each block is going to look like. That part of it is cached. And that cache is shared whether I'm on the search page, the posts page, the tags page, whatever. And it means published pages appear immediately without needing to deal with cache invalidation issues. Now, cache invalidation is one of the two hardest problems in computer science, alongside naming things and off-by-one
errors. If I change a page, I want the content to update. So how do I how does it know when that happens? Well, alongside introducing this tag in Micto 5. 2, we added the concept of a cache key. This is a customer attribute that exists on all of your pages and is tied to the content within it. You can use it for any other thing that you need to, if it changes, the cache key changes, and you can go from there. If a change gets published or a page gets moved, the cache key changes automatically. And if that's included is part of the caching for the template tag, which it is, then the template cache is automatically invalidated and it's regenerated. The old cache will eventually expire and be discarded. And if that's not enough and you want to manually clear the cache, you can do that too.
There is an API for that in the docs. Now, this concept might sound familiar to some. Django has had a template cache for quite a while. In fact, I had a look and it was introduced in 2007. That was long before even I was using Django. But it's dangerous to use this template tag unmodified with Wagtail. And that's because when you're loading a page in Wagtail, there's lots of different contexts you might be doing it in. For example, if you're loading a preview in the editor. You don't want those the content generated in a preview to be cached. It might contain old random content. You might have per-site settings that have the wrong value. that gets cached unexpectedly whether from a preview or something else. And a whole host of weird other bugs that come with caching.
But conveniently it is only a few small changes to change this over to Wagtail's page cache tag, which is a mouthful. And that wraps Django's template cache tag, but is aware of the current page and the site automatically. If you modify the page, the cache is automatically invalidated. If you use it on the same on different sites in White Tail, they're cached separately. And if that's not enough and you want to do something more manual, there is the Wagtail Cash tag. This doesn't automatically take into account the current page or the current site. But it does allow you to ignore preview requests automatically. So your preview and draft content stays private. And this makes it much closer in analog to um Django's cache tag. And generally If you're thinking you need a cache tag, you probably need either one of these two tags.
There is very little reason you need to use Django 's built-in caching tag. Now, part two, the second step for nicely perform uh improving the performance of your Wagtail site Is front-end caching. You can spend a lot of time optimizing the performance of your requests, caching common chunks of HTML, but not handling the request at all is even better. So, what if we put something in front of Wagtail to serve the requests instead? Maybe a CDN like CloudFront or Cloudflare or other brands that use the word cloud in their name. They can cache the page and serve it themselves. A CDN or content delivery network like these will help you generally in two main ways.
Firstly, they will serve a static copy of your website so your servers aren't processing every single request. And that allows you to handle many, many raw requests concurrently. Cloudflare, according to some information they published last year, handles 50 million requests per second across their global network. Your servers can't do that. You might think they can, they can't. And so this allows you to handle much more traffic with fewer servers. Your website isn't getting 50 million requests per second. I'm sorry, it's not that popular. But Cloudflare can handle whatever amount of traffic you will be getting. You can imagine this very similar to if you were converting your nice dynamic Wagtail site into a static site. When someone loads a page from the cache, there are zero database queries, there's zero templates, there are zero cachets, there are zero lines of code executed on your server, but the user's still got the page.
Secondly, said cache copy is stored much, much closer to your users. This map comes from Cloudflare with all of their different servers in various different parts of the world. And this helps reduce latency, it makes your site seem faster, and it can even help with your Google Lighthouse scores. And both of these things are things you're going to want to do as your website scales. Now, let's look at an example that you're probably familiar with, Wagtail. org. Wagtail. org is hosted in Dublin, which Yes, you can see that. Fantastic. Is in the east coast of Ireland. But I'm in Arnhem, where the other pin is. Um that's quite far away. In fact, it's about twenty-five milliseconds away across everything, or at least it was last night in my Airbnb.
Um and that's just the connection. If we tried to load the page from here The paid load actually takes almost 300 milliseconds, and that's a long time for a user to need to wait for every single asset. But when I open the white. org in my browser, It only takes twenty-eight milliseconds. How does that happen? Well that's the CDN. In our case, Cloudflare Now what actually happened was rather than loading the Wagtail page from the server where it is hosted in Ireland, it was hosted from a data center just outside of Amsterdam, I think. And that's only seven milliseconds away from me in Arnhem. And so that's much, much closer. And so instead of taking over 300 milliseconds to get a page, I'm getting just 28.
And the that means the users get what they want much, much faster. That 18 millisecond penalty is paid multiple times. It's not just something that is paid once per page load. It's not even something that's paid once per request. It can sometimes be paid multiple times for a given request. And if you've got your main HTML, three CSS files, 10 images, that time starts to add up very, very quickly. So let's stick a cache in front of all of our content and benefit from Cloudflare's massive network. Now it's reasonably easy to do. We just need to put something in between the users and our site. Requests get sent via the cache. If they're cached, they get returned from the cache. Otherwise, they will get the actual content directly served from Wagtail. Now we need to ensure that the CDN knows how long to cache pages for.
That's going to be somewhere between forever and one second. Somewhere between the hour is probably fine, but that's going to depend very much on your use case. And there are lots of different ways to configure exactly how the CDN is going to cache your content. There's various different headers. You might do configuration inside the CDN itself. If you're using Fastly, you're going to need to write a massive ton of varnish configuration. And there is in fact another talk about how to configure um caching with Wagtail and CDNs a little bit later on today. Now, you're gonna need to make sure that you skip the caching for any authenticated requests like the Wagto admin. These pages are dynamic generated based on who is viewing them. So we can't easily cache them and because they're generating much fewer white or admin editors it's so much easier to just skip the cache and have those go all the way through.
Yes, it's going to be slower. But that's generally a lot easier and saves a lot of complexity. A Wagtail does its best to make sure that the admin itself runs as quick as is physically possible, and that's what the performance team focus on. Fun. And so we need to know exactly how to do this will depend on your CDN configuration, and so you'll need to look into this. And so now content is cached. Pages load much, much quicker. Um server load should even drop drastically and you might be able to scale down to even fewer servers. Um according to some stats I pulled earlier this week, Wagtail serves almost Wagtail. org. serves around seventy percent of all page loads from the CDN. That means we're serving, what, almost four times as much traffic as our servers are capable of scaling to.
And so we reap those cost benefits by giving Cloudflare mu very little money in the grand scheme of things. And with a little bit of work, we could probably get that 70% number much, much higher. But uh oh, there's a typo on one of your pages. Um you can look at that image. The closer you look, the more horrifying it gets. Um And so it's easy. We open the page, we modify it in the Wagtail admin, and then we click publish. And that makes that's nice and easy through Wagtail. But the cache still has the old content, and so users are still gonna see that incorrect content. So how does the CDN know that the content has changed? Well, that's easy. Um It doesn't. Um the whole point is that it doesn't need to ask Wagtail with every request
what is the new content? That's the point of a cache So it can't know. The cache will expire eventually after an hour or however long you configured it. But what if it needs to go out sooner? What if Wagtail isn't actually written in Ruby? It's not. And what if it's more serious than just a typo? Well, this is where front-end cache invalidation comes in. Wagtail to the rescue with some magic Wagtail source that nicely makes our lives a lot easier. And what what front-end um front-end caching is, is a tighter integration between Wagtail and this content delivery network like Cloudflare. It allows Wagatel to instruct the CDN to clear its cache for a given page, purchasing the cache much, much quicker than just letting it expire. Cloudflare
have released some numbers and in fact they can get expires down to less than six seconds from when you ask it to around the entire globe, which is really, really quick. So how exactly does this work? That block shouldn't be there, but fine. Um step one, we need to add this little app into the installed apps. Step two, we need to configure exactly what CDN we're using and the various credentials. So this, for example, configures the Cloudflare backend with the token and zone ID that we need for Cloudflare's API And that's it. All of the hooks are already in the right places and set up for you so that when you publish a page, the right pages get configured. Get cached, uh get purged. And you can configure that if you need to. For example, if you're editing a blog post
page and when you hit publish, you need the listing pages it's referencing on. to be cleared as well, you can do that nice and easily. There are various different hooks, all of which are documented to expose that extra caching functionality. So when you publish a page, it'll automatically be cached. It can take a minute or so, depending on your CDN, but it's often much faster than that. And then when a user goes loads the page, they end up requesting it from Wagtail, that result is cached, and subsequent loads go back to being nice and fast. So, in conclusion, when most people think of performance, they tend to think of database queries. And that's true. That is generally where a lot of time goes. But there's a lot more to optimizing a site than just sprinkling select-related or prefix-related around your site.
Performance means a lot of different things to a lot of different people. Your application is made up of a lot of different components, and so too must your performance investigations. It's faster to do a lot less than to do a lot more, but it's faster still to do nothing than to do something. The higher up the stack your cache is, the more impactful it can be. More of your code gets cached, but slower pages are still slow, even if they're not called as often. And so why repeat yourself? Make things faster. Performance, it means your users are happier, means your servers are happier, and because they're caching and doing a lot less work, the planet is happier. Thank you.
Wrap the component’s HTML in Wagtail’s page cache template tag, setting a time to live, a unique fragment name, and any values the cached output should vary on. The cached fragment can then be reused wherever the template is included with the same context.
Discussed at 5:36Wagtail updates a page’s cache key when it is published or moved. Because the page cache tag uses that key, the old fragment is no longer used and is regenerated; there is also an API for manually clearing the cache.
Discussed at 8:42A CDN serves cached pages without sending every request to your Wagtail server, reducing server work and helping the site handle more traffic. It also serves content from locations closer to visitors, which reduces latency.
Discussed at 11:50No. Skip caching for authenticated requests such as the Wagtail admin, since those pages are generated dynamically for each user; letting them go directly to Wagtail is simpler and safer.
Discussed at 15:08Wagtail’s front-end cache integration connects to a CDN such as Cloudflare and purges the relevant cached pages when content is published. You configure the CDN backend and credentials, and can add related pages—such as a listing page—to the purge when needed.
Discussed at 17:30Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published June 27, 2024
Published June 27, 2024
Published June 27, 2024
Published June 27, 2024
Published June 27, 2024
Published June 27, 2024