Monolithic applications may not be all the buzz today, but many (WordPress, Ruby on Rails, Laravel, etc.) are alive, active, and still heavily used.
In fact, one major benefit to not being all the buzz is that “the buzz” has evolved far enough in the last several years that many modern patterns can be applied to more traditional means of building websites and applications.
Here, we’re going to look at islands architecture. It’s a paradigm that has been talked about for a couple years, but has been getting more attention recently. Similar paradigms are used in new features just released in Next.js 13 (one of the most popular modern frameworks), hinting that this type of pattern has enough support to evolve into the mainstream.
Islands architecture explained
Our goal here is to explore how we can take advantage of the benefits of islands architecture when working with a monolithic application. Let’s first look at determining exactly what islands architecture is to better know if it’s the right move for your application.
The history of HTML rendering patterns
To understand how islands work, let’s first look at an overly-simplified history of rendering HTML on the web:
- SSR: Monolithic frameworks (WordPress, Ruby on Rails, Laravel) traditionally compile HTML using server-side code and send that code to the browser at the time of the request — i.e., server-side rendering (SSR)
- SSG: The introduction of Netlify and Jamstack commoditized delivering static content using a CDN, with an inbuilt mechanism for cache invalidation. Almost overnight, this made static site generators (SSG) cool again. With SSGs, the server pre-renders the entire set of HTML pages for a site during a build process and makes them available to users via a CDN. This was revolutionary but created additional challenges for large sites (long build times, lack of previewability, cost, etc.)
Rendering revolution vs. evolution
At first glance (and without much nuance) this history seems to hint that we’re back where we started, almost two decades later.
DHH on Twitter: “The pendulum is finally swinging back, and with the force of a wrecking ball. May the towers of needless complexity built in the past decade be smashed to smithereens 💥🔨 https://t.co/PPGUB2U6Af / Twitter”
The pendulum is finally swinging back, and with the force of a wrecking ball. May the towers of needless complexity built in the past decade be smashed to smithereens 💥🔨 https://t.co/PPGUB2U6Af
The irony of the popularity in rendering via the server, then the client, then the server again is obvious. But it’s not that simple. Each revolution has been an evolution in creating a better developer experience for the web and, frankly, to make building for the web more accessible to more people.
Finding the best of both worlds: Progressive hydration
In the years since Next.js has gained popularity, countless tools have emerged to try to solve how find the perfect balance of performance and developer experience.
The common pattern that has emerged generally centers around what we call progressive hydration. With progressive hydration, HTML is sent to the browser from the server. This can be via SSR (built on request) or SSG (prebuilt).
This paradigm is what Next.js and others use to enable developers to use UI frameworks like React to build the entire UI with components, and separately choose the most effective means for delivering that content to the browser.
Islands vs. progressive hydration
There are some great introductory posts to islands on these sites:
- JASON Format
- Astro (generally considered the first framework to focus on the approach)
Architecture is continuing to evolve
Before we move on, it’s important to recognize that we’re not at the end. New optimizations and patterns are constantly emerging. The recent release of Next 13 using React Server Components along with Shopify acquiring Remix are two stories that are continuing to find new ways to optimize that balance between developer and user experience.
Benefits of islands architecture
There are a number of benefits to the islands approach, but most are contextualized with improving upon existing frameworks that ship dependencies that could be handled on the server. For small and/or mostly static applications, it absolutely makes sense. It’s a great choice.
Instead, let’s consider what I find to be the two primary benefits in islands versus traditional SSR monolithic frameworks:
- Organization/UI scalability: Islands means thinking about components. Building a UI with components is so much easier to manage and scale than traditional HTML partials and gigantic CSS files
Tips on “migrating” to islands from monolith
You can take advantage of islands architecture in your monolithic application in a few different ways. And they don’t necessarily mean migrating. It’s about changing your way of thinking about the interactivity on your site.
Manually adjusting your current implementation
Vanilla web components
You may have heard of web components. They seemed cool for a minute or two. Well…they’re back! And that’s in large part thanks to ideas like islands architecture.
Frameworks like Lit and Stencil have been around for years and can still be used, but (in my experience) are difficult to implement in a scalable, island-like way that meshes well with other tooling.
The 11ty team also has another project in the works called is-land, a web component that hydrates itself based on some specified event (for example, when it appears in the viewport). is-land is a single script that is also meant to be framework agnostic, although it works best with 11ty. This is worth considering in addition to WebC, or even on its own with your custom implementation of rendering web components.
You may not want to use these frameworks or libraries directly, but you can use them to develop a solution that would better suit you and your tooling.
Send HTML over the wire
As these UI frameworks were gaining incredible popularity, the folks over at Basecamp (creators of Ruby on Rails) developed Hotwire, a tool for wrapping server-side actions in isolated sections of the page without reloading the page. It simply gets the resulting HTML back from the server response and replaces only that portion of the page.
There may be a tool like Hotwire available for the framework you’re using.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to animate your React app with AnimXYZ
- Explore Tauri, a new framework for building binaries
- Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
In other words, this approach only gets you part of the way to a true islands approach to your frontend code.
Gradually migrate to a modern framework
And last, there’s always the nuclear option: rebuild!
If you want the benefit of modern web patterns, but the previous ideas feel like too much customization or effort, it may be time to upgrade your frontend.
Of course, it always feels like a lot when we’re talking about upgrading an entire application. But it doesn’t have to be. You can do this one piece (page, route, etc.) at a time, making it a gradual migration, or a strangler fig application.
The way that many migrate from monolith to a more composable approach is to build your front and back ends separately, which is likely an easier path because you won’t have to move your data. Instead, your current application slowly becomes an API-only app, while you spin frontend pages off into a new application.
Pick the path that works for you
As you can tell, this isn’t a one-size-fits-all sort of migration. There are many types and sizes of monolithic applications today. And there are many ways in which you can achieve the benefits of an islands-like approach to your front-end code.
If nothing sounded immediately obvious or beneficial, I’d suggest trying a small-scale implementation of a few approaches within your current system. If something feels right, you take it a little farther until you have the confidence that it can scale to serve your entire application. Or you move on to try the next thing.
Get setup with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()must be called client-side, not server-side.
- (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
import LogRocket from 'logrocket';
Add to your HTML:
<script>window.LogRocket && window.LogRocket.init('app/id');</script>