- 17 minutes read

Let's talk about the new kid on the block. The islands architecture answers the ever-growing challenges of the popular single-page architecture (SPA). Well-written SPA applications offer superior UX. That's why tools like Gmail and Google Maps became popular in the early 2010s.

Before 2010, every web application did a full-page submit after every user interaction. The browser showed a white page for one or two seconds while the server pondered the response to the user input. SPAs changed that. They brought seamless interactivity to the web, eliminating the eye strain and headaches many employees suffered from.
That's not a big deal in an office with a generous internet connection, but it's painful in a rural area with slow internet on a mobile device. The island architecture aims to improve that without losing the advantages of SPAs.

I've been experimenting with the islands architecture for a couple of weeks now. I'm impressed. This architecture is a good match for web applications using micro-frontends. It's also ideal for blogs and web pages that are mostly, but not entirely, static.

What is the islands architecture?

Have a look at a web application. It doesn't matter which one - you'll probably notice static and dynamic parts in such a web application. Typically, these parts are independent - or mostly independent - of each other, so let's call them "islands." There are islands of interactivity surrounded by an ocean of static HTML that's nonetheless important. Sometimes, the static parts dominate, and sometimes, your application's interactive components cover most of the screen estate. But the idea of dynamic islands swimming in a largely static ocean is almost always a helpful abstraction.

An illustration showing large an small islands in the ocean. The small islands symbolize the static content, the large islands stand for the dynamic content.Image published by Missing author!
on Missing publisher! under a (C) 2023 Stephan Rauh.
For example, a typical blog is chiefly static. The average webshop looks very dynamic, but if you're ready to render the product pages on the server, you can convert it to a mostly static page with a few dynamic islands. That's the idea of the island's architecture. It makes sense to convert a large part of your application to static pages because web servers deliver them fast and efficiently, and the browser can render the page immediately.

In contrast, most enterprise applications are almost entirely dynamic, especially if they're available on the intranet only. Even the menu isn't static. Every user sees different menu entries depending on their access privileges. But even such an application can benefit from the island's architecture. The magic word is "micro-frontend". The islands architecture makes it easier to split your application into distinct micro-frontends.

Advantages of the islands architecture

The islands architecture aims to divide your application into a collection of static HTML fragments that can be sent to the client quickly. Static HTML pages and fragments can be cached efficiently, allowing you to leverage the full power of a CDN like Cloudfront.

From an SEO perspective[1], static HTML has another considerable advantage. The search engines detect your page a lot faster. The last time I checked, it took roughly three days until a new article on my Angular-powered blog appeared in the Google index. Serving static HTML cuts this down to a day and usually much less.

If you're working on a big enterprise application, there's another, even more exciting advantage. The islands architecture frameworks make composing an HTML page from smaller fragments easy. This shows in my experiments with Astro: I end up with a clean structure of components that's easy to understand. The components themselves tend to be simple, too. The complexity of your application hasn't gone away, but now it's located inside the dynamic islands. That helps you to cope with it. The rest of the application is simple HTML code connecting static and dynamic islands.

A practical example: which static and dynamic islands does BeyondJava.net have?

Too much theory? Let's have a look at the blog you're currently reading and how it divides naturally into static and dynamic islands:

A sketch of the decomposition of the visitor statistics page of BeyondJava.net. It's explained in the text below.

The header, the menu, and the disclaimer are static components that hardly ever change. <article /> is a component contributing CSS code to ensure the text is centered. Similarly, <header /> is a component that's responsible for showing the cloudy image and the title of the article.

It goes without saying that <header /> shows a different title for each article. The page's structure is always identical, but the header still varies depending on the URL. That's an interesting corner case. <header /> is still a static island. There's no interactivity. You can render the page on the server, and it doesn't need JavaScript on the client.

The idea of the island architecture is to generate the HTML code of <header /> on the server, delivering different code for different URLs. The browser receives simple HTML. The code showing different text for different URLs has moved to the server. If you need more speed, the server can cache the HTML fragments. Alternatively, you can pre-render the HTML code for every conceivable URL in advance and store it as a collection of static files on the server.

Remains the <visitor-statistics /> component. This component uses some fancy D3.js code and accesses the database to generate the images. This is a dynamic island. An even more convincing example is the <write-comments /> component, which allows you to compose and submit a comment. That's interacting with the user. In 2023, nobody wants to use a server roundtrip for simple tasks like validating the input, so it's an obvious candidate for a dynamic island. This part of the blog isn't fun without client-side JavaScript.

Server-side rendering can help us even with the <write-comments /> component. I'll cover that in a minute.

Micro-Frontends in the islands architecture

Both the <visitor-statics /> and the <write-comments /> components are isolated components accessing their own back-end. Isolated means you can put them into dedicated projects and compile and develop them independently from the rest of the project.

That's the idea of "micro-frontends": they consist of a part of the front end and the corresponding part of the back end. A dedicated team can easily implement such a micro-frontend without caring about the rest of the application. There's a clearly defined interface; apart from that, you're independent. You're living on your own island.

The islands architecture supports this pattern particularly well. In other words, the islands architecture helps you to isolate your micro-frontends.

WebComponents are a sophisticated approach to building components in HTML and JavaScript. From the outside, they look like user-defined HTML tags. Inside, they consist of JavaScript code. Modern UI frameworks like Angular or React allow you to encapsulate arbitrary components as WebComponent. WebComponents are both self-contained and encapsulated. They offer a thin, well-defined interface (attributes and events) but little beyond that. There's no risk they interfere unexpectedly with the rest of your application.
The dynamic islands only need to load the binaries generated by the micro-frontend build pipeline. This approach ensures a clear separation of concerns.

Of course, that's not what the people writing islands architecture frameworks want to show you. They want to show you that - for instance - React is a first-class citizen of their framework, as this Stackblitz example shows. That's awesome, no doubt about that. Just keep in mind that this approach supports small-to-medium use cases. It backfires when your micro-frontend consists of dozens or hundreds of source code files.

Frameworks

Talking about frameworks, there are plenty. Just to name a few: Marko, Astro, Qwik, Alpine.js, 11ty, and Fresh. To be honest, I can't say much about most of them. I've been experimenting with Astro for some time now and am excited. It solves a problem I've been gnawing at for some time and matches my thought patterns. So, I'm afraid I haven't looked at the other frameworks yet. They might be superior. But Astro already did the trick for me.

In other words, my praising Astro doesn't say anything about the other frameworks. Because I won't look into them soon, you may look at them to decide which one works best for you. If you do, I'd like to hear from you. Please send me an email or a comment so other readers benefit from your insight!

Historically, Astro started as a framework generating static content. You can compose your page from smaller components and apply a layout to a page. The result doesn't differ much from what you do when writing a React, Vue, or Angular application.

Server-side rendering

Nowadays, Astro also offers server-side rendering. To be precise, there are two closely-related meanings of "server-side rendering," and Astro supports both of them:

A purely decorative image. It's what the AI tool DALL-E suggested when I asked it to draw an image about server-side rendering.Image published by Missing author!
on Missing publisher! under a (C) 2023 Stephan Rauh.
The first definition applies to SPA frameworks like React, Angular, and Vue.js. These frameworks allow you to pre-render your component. This means that the initial HTML page - what you see before the first user interaction - is generated. The browser parses this "dry" HTML page almost immediately. From the user's perspective, the HTML page is there when they click. There's no perceptible delay.

However, that's where the magic kicks in. The dry HTML page isn't interactive. Modern UI frameworks bring this HTML code to life by sending their JavaScript code later. That's called "progressive hydration". The HTML code is animated in the short time the user needs to grasp the page.

The second (and more traditional) meaning is what you do in native Astro components. You can use JavaScript code to customize your HTML code. Generally speaking, you shouldn't use too much JavaScript code because that would slow down your server. On the other hand, you can access all the information available on the server, which is much more than what you can send to the client.

The result is fascinating. You can implement quite a few things on the server. The difference between implementing code on the client and rendering it on the backend blurs. For example, you can quickly implement a full-text search for a blog because the Astro backend gives you access to every page.

Technically speaking, server-side rendering is what we did before the invention of AJAX and SPA in the 2010s. The key to success is to use SSR when a fast, initial response is required. In every other case, SPAs are the better choice. Dynamic rehydration is a clever compromise: sending a skeleton of the application's HTML code to the client quickly and starting the application during the time the user needs to read the page. That's what the island's architecture is about: allowing you to choose the best tool for each island.

Server-side rendering takes the islands architecture to another level. For example, I fondly remember a webshop project where we decided to render every product page in advance. The prices may vary daily, so we ran a batch generating all the product pages each night to be up-to-date, with a delay of up to 23 hours.

Server-side rendering allows you to get rid of the delay. Instead of rendering the page in advance, you render it on demand, thus reflecting the current state of the database. As a side-effect, you save a lot of disk memory.

Living on the edge

I've even seen an article describing how to do server-side rendering with AWS Lambda@Edge with Astro. This sounds very attractive: you benefit from serverless computing, and your code is rendered in your customer's region, thus ensuring minimal latency. I suppose there's a price tag - traditional AWS Lambdas are cheaper if I'm not mistaken - but using Cloudfront to cache popular pages keeps costs in check.

Lambda@Edge allows you to run a JavaScript function directly in the CloudFront CDN. This means the function is executed in the vicinity of the user. This approach shaves off a couple of milliseconds. The disadvantage is that only the cache of this particular user's region is populated. When another user living somewhere else requests the same page, it has to be rendered and cached again. This also leads to higher costs: the cache is less efficient, and the Lambda runs more frequently than a traditional Lambda. Of course, that's only a topic if you're addressing an international audience. If all your traffic is in the same Cloudwatch region, you only have to keep the slightly higher base price of Lambda@Edge in mind.

I've briefly experimented with this idea. After a short love affair, I ran into the limitation of Lamda@Edge. These particular Lambdas are limited to 50 MB. More likely than not, that's not a big deal for you, but it was for me: my blog's memory footprint is close to the 50 MB threshold. So, I reverted the experiment and disabled server-side rendering again.

Of course, the Astro server hasn't been written with Lambda@Edge in mind. It's a traditional node.js server so that it can run on EC2 or Fargate. I shied away from setting up such a server because of the costs. It'd raise my AWS fees by roughly 20 to 50 dollars. That's negligible for a corporate project but a bit heavy for my private blog. AWS Amplify or traditional Lambda might be decent alternatives, but I haven't tried Astro on either service yet.

Astro's native support for popular UI frameworks

Astro seamlessly supports React, Vue, Svelte, Preact, and several other UI frameworks. That's awesome, but in my opinion, you should think twice before going down this rabbit hole. As usual, it depends on your use case. If you've got a simple component consisting of one or two classes, go for it. If your micro-frontend requires more than 100 classes, I suggest setting up a dedicated project, wrapping it as a WebComponent, and copying the binaries into your Asto project.

If you're somewhere in between, well, you've got my message. Please do whatever you want, as long as it's a simple solution. And don't forget to ask your co-workers. Their definition of simplicity might be different.

What about Angular?

Angular has been written with a different mindset than React, Vue, and Svelte. Of course, the Angular team is aware of current trends and opens its framework to those trends, but the general idea of Angular is it owns the entire page. Angular applications tend to have a huge memory footprint and a noticeable start-up time. That's not a big deal in a vast monolithic enterprise application, but it shows when your Angular application is just a tiny island of your web application.

I've successfully converted the visitor counter of my blog into an Angular stand-alone component, put it in a dedicated project, and copied the binaries to the public folder of the Astro project. That's a folder Astro promises to copy as-is to the final deployment. The problem is this doesn't seem to be true. It worked for the visitor counter, but when I tried to add a second Angular component, Astro started to validate the generated code and complained about errors.

That's weird and indicates that Angular components aren't guaranteed to work. On the other hand, I ran into the same problem with a React component using the native Astro integration. Maybe this shows that the technology is still young (or I lack experience with it). The good news is that if you start on the green field, you should be able to cope with this. I only ran into trouble trying to reuse components from other projects.

By the way, looking at the current progress of Angular, there's hope. Angular 17 looks like a giant step forward. I suspect (or hope?) Angular is moving towards more flexibility. I'm optimistic it will become easier to create a small Angular widget and integrate it into another application. Angular itself is already there if I'm not mistaken. The heavy memory and performance footprint stems primarily from third-party libraries. That's good news: sooner or later, they'll catch up, and when they do, Angular might become a first-class citizen in the Astro universe.

What about Single-Page Applications?

Converting your application to a static HTML page helps your Google ranking and makes your SEO team happy, but what about the user experience? In an islands architecture, every link triggers a full-page request.

That's a painful regression. We've spoiled our users for one or two decades with AJAX and single-page applications. Going back to the old request-response paradigm is not an option. We might get away with it if it's so fast nobody notices, but I wouldn't bet on it. Sooner or later, we all are in a 3G area with an old cell phone.

Astro has an exciting solution for this. Adding the <ViewTransitions /> component to the header of your page converts the Astro application into a Single-Page application. It's not as efficient as Vue or React, but it's simple and works surprisingly well. The number of requests is reduced significantly, and navigating from one page to the next feels much smoother.

Wrapping it up

The islands architecture is an interesting approach to modularizing your front-end. It's popular for blogs and webpages, but not limited to that. I'm positive it also simplifies the development and usage of micro-frontends. The bad news is I don't see how to convert an existing application to Astro with reasonable effort. So in the short term, Astro, in particular, and the island's architecture, in general, are primarily green-field technologies.

A purely decorative image. It's what the AI tool DALL-E suggested when I asked it to draw an image about Astro. It shows an ocean at night, a lot of stars and something that might be a galaxy behind huge dust clouds.Image published by Missing author!
on Missing publisher! under a (C) 2023 Stephan Rauh.
Taking Astro for a test ride was pretty exciting. Granted, I ran into minor problems, especially when integrating my Angular micro-frontends. But I expected this because I tried to reuse my battle-tested Angular components without changes. I'd written them with a different mindset. I didn't optimize them for a low memory footprint or easy integration.

If you start a project from scratch, or if you've got the opportunity to fine-tune the code you're reusing, you'll love the islands architecture, no matter whether you're using Astro or one of it's competitors.

Kudos

Special kudos go to Ylva Spörle who helped me to improve this article.

Dig deeper

Jason Miller on the islands architecture

In-depth coverage on patterns.dev

How to do server-side rendering with AWS Lambda@Edge with Astro

Astro JS Framework: A Practical Guide To Building Faster Websites


  1. SEO - search engine optimization - is the art of optimizing a web application so that the web application shows on the first page of your Google search result.↩

Comments