Modern software development relies heavily on reusing existing frameworks, libraries, tools and approaches, and combining them in exciting, new ways. It's much like what we do with LEGO bricks. Let's take a look at a few ways we can combine the building blocks of a headless architecture and how, despite using the same elements, the outcomes differ in ways that matter.
What is this whole architecture about?
I'm pretty sure you must have heard about architects. Well, not those that specialize in designing buildings but those that design IT systems. The name actually is not accidental here because developing software is quite similar to building houses in various aspects and required roles.
You can also compare developing software (that starts with proper architecture) to building constructions from LEGO bricks. Nowadays, there are a plethora of tools, frameworks, services and approaches you can choose from. Imagine all those are LEGO bricks. When starting a project, you are faced with a dilemma of which bricks to choose.
Now, it is the architect's role to find the proper bricks and create instruction on how to combine them together to deliver the expected value. You pick the wrong brick and sooner or later the construction will fall down. And that's only part of the fun. Ideally, you also should be able to interchange those bricks or add new ones to let your construction grow. Yeap, I know, no one said the life of an architect would be easy.
The ultimate headless architecture
Well, let me be honest with you: there's no such a thing as the ultimate architecture, be it headless or any other. But wait, didn't I name the article "The ultimate headless architecture"? Don't blame me, I'm pretty sure it is neither the first nor the last clickbait you have been poached with. And that's not my fault, it's just that every customer's needs are unique and the combination of required services is unique too. Hence, as a consequence, each architecture is unique.
But fear not. It's hard to explain any architecture looking at super complex diagrams. Instead, we can start simple and focus only on the content part. That should no longer be that scary. Then, we can just keep adding the bricks to let our architecture grow. It's nothing different from a LEGO set, you never start with the last page of an instruction. You start with the first one. And that's what we are going to do in this article.
The headless set of bricks
Let's agree that in this article we will focus on the web channel. You may feel disappointed, but most customers start (and finish) with the web channel, which is still the most important one these days. And secondly, it should not be that hard to extend the architecture to other channels if you know how to deal with one of them. As much as possible, I tried to keep the description channel-agnostic, though.
If you review all the bricks out there, you will find out that to build our LEGO set we need only three of them. These are:
- Headless CMS - your content platform
- Code repository - the place you keep the source code of your application (web in our case) - the missing "head"
- Hosting platform - the place to serve your application from
Please note: it doesn't matter what vendor you choose for hosting, headless CMS, or code repository. The bricks still will be of the same shape only the colour (or their shade) may change.
Ok, so we've picked the bricks, but that's only the start. The way you combine the same LEGO bricks can give you completely different results. You can either use the trial and error method or you can use building instructions. The former may seem to be more fun, but you may need to rebuild it a few times. The latter, on the other hand, guarantees your construction will look exactly as promised, and the fun depends on your attitude! So without further ado let's see what instructions we have.
Note: Next to each method's name in the brackets I put the name specific for the web channel
- Static build time delivery (Static Site Generation - SSG)
- Dynamic on server delivery (Server-side rendering - SSR)
- Dynamic on device delivery (Single Page Application - SPA)
- Hybrid static/dynamic delivery (Incremental Static Regeneration - ISR)
Non-technical explanation
IMPORTANT NOTICE: a few paragraphs down you will find a very technical, developer-friendly description of those instructions with proper diagrams. However, personally, I love to be a link between the IT world and the world of non-technical people. To make it more approachable for less technical readers, let me first explain those instructions in a simplified way.
Let's use the LEGO analogy again, but in a slightly different context. Imagine you have a warehouse full of LEGO bricks, but you want to sell LEGO sets to your customers. So, you set up a store. Here are the business models you may want to consider.
Static build time delivery a.k.a. “I have ready LEGO sets for you” business model
Let's assume you know what kind of LEGO sets are popular at the moment, e.g. LEGO Castle or LEGO Pirates. So, you collect all the required bricks and pack them in advance into shiny boxes. When a customer arrives at your store, they can pick a ready set, pay for it and leave. They have been served quickly and they are happy.
Dynamic on server delivery a.k.a. “Let me create a favourite LEGO set for you” business model
But what if your customer is particularly demanding and when they arrive at the store, it turns out all the sets are passé now? What would you do? Get rid of all the sets in front of the customer, go to the warehouse and prepare a bunch of new LEGO sets from which they can choose their favourite one? No, it wouldn’t look professional. But, you already know what is trending now, so you can quickly assemble a new set for the customer. Well, of course, the customer will have to wait a bit until you pack all the bricks. Still, they will be served with what they really want. Because you already know what sets are trending now, you can assemble more of those. Next time a customer comes you are ready and you can serve them quickly.
Dynamic on device delivery a.k.a. “DYI” business model
Now imagine you never know what your customers may want, so you do not prepare any LEGO sets in advance. Instead, when a customer arrives, they can pick all the single bricks they want and assemble the LEGO set of their dreams by themselves. Well, of course maybe they won’t be served quickly, and perhaps they may pick more bricks than needed. On the other hand, running such a store should be pretty cheap, as you do not have to pack the LEGO sets by yourself, and you can spend the time on something more productive, maybe better enjoy your customers.
Hybrid static/dynamic delivery a.k.a. "If you don't find your favourite LEGO set, I will do it for you" business model
Let me put it simply. It's just the combination of the first two business models. Give your customers a promise, they can pick a ready LEGO set or, if they don't find what they are looking for, you can prepare something for them on the fly.
Technical explanation
If you feel like you are ready for something more technical, keep reading.
Static build time delivery (Static Site Generation - SSG)
The artefacts (things that deliver the content to your users - pages in the context of the web channel) are generated in advance before they are even requested by end-users. They are generated at timed intervals or based on some event e.g. code push, content changes etc.
Typical SSG update cycle
- Content editor creates content in headless CMS
- Either due to content changes, on schedule, or due to changes in the application's codebase, your CI/CD (Continuous Integration and Continuous Delivery) build is triggered
- CI/CD starts building pages
- CI/CD pulls content from headless CMS to statically generates pages
- CI/CD uploads generated pages to your hosting solution
- The end user requests a page
- The page is either served from CDN's cache (depending on the caching policy) or, if not yet available there, requested from the static hosting
Note: you don't need a CDN, it is just that it gives you so many benefits that it would be shame not to.
When to use
Imagine two sliders. One controls the number of pages and the other frequency of updates. This is the main factor one should consider.
The more you go right with the first slider the more you should consider going to the left with the second slider. Why is that? Because SSG generates the whole app each time it is built so the more pages you have the longer it takes to regenerate them.
When you start paying more for your CI/CD than you would pay for on-demand generation (see next instruction), or you lose money because your content is too often stale for end-users, then you should consider a different approach.
Pros:
- hosting - statically generated pages are cheap and simple to host
- performance - statically generated markup is fast to serve and render in the browser
- secure secrets - your tokens and secrets are never exposed as they are used only on the backend
- SEO - statically generated markup is more easily digestible by search crawlers. What's more, it's much faster to index than content generated by JavaScript. This translates to SEO benefits
Cons:
- generation time - it takes time and resources to regenerate pages, which can be problematic with frequent content changes and lots of pages to generate
- stale content - until you build your artefacts again your users will see stale data
- process - if your artefact is a native mobile app then updating it and publishing to e.g. Google Play Store or Apple's App store takes a significant amount of time (it can take even more than 24 hours!)
Dynamic on server delivery (Server-side rendering - SSR)
The artefacts are generated on demand when they are requested for the first time by an end user.
- Content editor creates content in headless CMS
- Developers push codebase changes (this can happen anytime)
- End user requests a page
- The page is either served from CDN's cache (depends on caching policy) or, if not yet available there, requested from some computing services (this can be either lambda functions or some server resources)
- Computing services pull both content and code of the application to generate output markup of pages, which are then returned to the end user
Note: CDN is highly recommended here otherwise every request would consume server resources which are expensive in comparison to static hosting.
When to use
Look at these virtual sliders again. If you move the pages slider to the right (you have more and more pages) and you move the frequency slider to the right (you want to update more and more frequently), you may end up with constant regeneration to ensure your users are not served stale content. In other words, if your content changes often or the content cannot be known during the build time, then this method is perfect for you.
Pros:
- reactive - depends on your caching strategy, but in general, your content is considered always fresh / no stale content
- performance - statically generated markup is fast to serve and render, however, unlike with SSG we may experience a few milliseconds of delay with the first uncached request (that's formally called latency)
- SEO - similar as with SSG
Cons:
- cost - more expensive due to server services required
- external caching such as CDN is highly recommended (not only optional)
- page latency - if the page is not yet in the cache, it will take a few more milliseconds before it's generated
- error rate - depending on your setup, e.g. lambda functions vs server, the the error rate is potentially much higher than with SSG
- higher quota on headless CMS API is needed because you are going to query the content more often than with SSG. It's not about the performance, because all the major headless CMSs serve content through their own CDN, but even though the traffic goes through the vendor's CDN it's billable per request.
Dynamic on device delivery (Single Page Application - SPA)
The end user downloads a client-side application. When the application is launched / web page opened, a request or series of requests is made to the headless CMS for the content. The artefacts are generated on the end user's device (be it web pages, mobile app views or anything else).
- Content editor creates content in headless CMS
- Developers push codebase changes (this can happen anytime)
- CI/CD starts building the application (note that it builds only the application, not pages)
- CI/CD uploads generated application to your hosting solution
- End user requests for a page, but downloads only the artefacts responsible for launching the application (from static hosting through CDN)
- The application launched on end user's machine requests for content and generates markup of pages
When to use
This kind of architecture is a best fit for app-like websites (usually behind a login screen), e.g., dashboards, admin panels, widgets etc. Another common use case is to render user-specific content. It can be used for regular websites, however SEO and client-side performance will suffer a few precious points in search rankings, if not properly treated.
Pros:
- simple - the architecture and flow are very simple
- hosting - statically generated app is cheap and simple to host
- reactive - your content is always up-to-date
Cons:
- higher quota on headless CMS API needed - because every request for content always goes to the headless CMS
- SEO - heavy JS applications are more challenging for search crawlers
- performance - Single Pages Apps, when already loaded by the browser, are very fast. However, the first (initial) load takes more time and resources, which can also impact your SEO rankings.
- secure secrets - all the logic is implemented and executed client side. Hence, without introducing a middle layer, you won't be able to hide any secrets or tokens.
Hybrid static/dynamic delivery (Incremental Static Regeneration - ISR)
Hybrid delivery allows having the best of both worlds of the Static and Dynamic on server approaches. This approach is about generating artefacts during the build time, but allowing for dynamically rebuilding them either after some period of time, or on-demand. Here, rebuilding is not that expensive, as not the whole application is rebuilt, but only parts of it.
If you look closely at the picture above, you should see similarities to other, previously described instructions. As an exercise, try to analyse the flow on your own.
When to use
A perfect use case is when most of your pages are known during the build time and it's highly unlikely that they will change. Or maybe you know they will change, but very seldom, or that only a limited subset of them will be affected.
Conclusion
As you can see, if you focus only on a single problem, the architecture for it will be simple. If your problem seems to be too hard to solve, always try breaking it down. And the last word, do not limit yourself. If you have ever built anything from LEGO bricks, I'm pretty sure you then dismantled it and built something again, but differently. Try the same with the above instructions. Why don't you combine a few approaches for the same problem? Maybe parts of your website are perfect candidates for Static build time delivery whereas others are ideal for Dynamic on-device delivery? Feel free to experiment. That's why someone invented LEGO bricks after getting bored playing with a "monolithic" toy...
Batman photo by Studbee on Unsplash
LEGO street photo by Alphacolor on Unsplash
Random set of LEGO bricks photo by Rick Mason on Unsplash