How to solve coordination problems in Island architecture

Island architecture isolates interactive UI fragments into independently hydrated units. Each island sends only the JavaScript it needs, reducing hydration costs and improving performance.

However, this isolation creates coordination problems.

When one island needs to affect another island, there is no shared runtime context by default. The cart badge should be updated when the product island adds items. The filter island should affect the result island. Authentication state must propagate across boundaries.

This tutorial discusses how to accomplish cross-island coordination without sacrificing the performance guarantees that make Island architecture attractive. You will create a minimal example, see why localStorage polling fails, and replaces it with an explicit event-based model that supports asynchronous server updates.

Ultimately, you will understand how to coordinate islands while maintaining isolation, testability, and SSR compatibility.

Coordination problems in Island architecture

Frameworks such as Astro, Qwik, and Fresh implement the Islands architecture by isolating interactive components into separate client entry points. Each island has its own state and life cycle.

Such isolation reduces hydration costs, but eliminates implicit shared states.

Coordination problems arise when one island needs to react to state ownership by another island:

  • The cart badge is updated once the product is added
  • The notification island responds to authentication changes
  • Filter panels that affect the results list

Direct imports between islands broke down architectural boundaries. Reading global state introduces hidden coupling. Polls pose a timing problem.

We will work within three constraints:

  1. The islands remain independently hydrated
  2. No direct cross import
  3. Coordination must remain explicit and observable

Project structure

We’ll create a minimal example with two islands: ProductList And CartBadge.

islands-coordination/
  server/
    server.js
  public/
    index.html
    product-list.js
    cart-badge.js
    event-bus.js
  package.json

Wrong approach: Using localStorage as a communication channel

localStorage looks interesting:

  • This is global
  • It’s persistent
  • It requires no setup

But this creates implicit pairing and timing hazards.

Step 1: Set up the server

Make package.json:

  "name": "islands-coordination",
  "type": "module",
  "scripts": 
    "start": "node server/server.js"
  ,
  "dependencies": 
    "express": "^4.18.2"
  

Install dependencies and build server/server.js:

import express from "express";
import path from "path";
import  fileURLToPath  from "url";

const app = express();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

app.use(express.static(path.join(__dirname, "../public")));

app.listen(3000, () => 
  console.log("Server running at 
);

It presents static assets from public/.

Step 2: Determine the island entry point

Make public/index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Islands Coordination</title>
  </head>
  <body>
    <div id="product-island"></div>
    <div id="cart-island"></div>

    <script type="module" src="/product-list.js"></script>
    <script type="module" src="/cart-badge.js"></script>
  </body>
</html>

Each island is hydrated independently through its own module.

Step 3: Product island writes to local Storage

public/product-list.js:

const root = document.getElementById("product-island");

root.innerHTML = `
  <h2>Products</h2>
  <button data-id="1">Add Product 1</button>
  <button data-id="2">Add Product 2</button>
`;

root.addEventListener("click", (e) => 
  if (e.target.tagName === "BUTTON") 
);

Step 4: Poll cart island Local storage

public/cart-badge.js:

const root = document.getElementById("cart-island");

root.innerHTML = `
  <h2>Cart</h2>
  <span id="count">0</span> items
`;

const countEl = document.getElementById("count");

function readCart()  "[]");
  countEl.textContent = cart.length;


readCart();

// Poll every second
setInterval(readCart, 1000);

Why this failed

This implementation raises several architectural issues:

  • Polling wastes CPU cycles
  • UI updates lag by up to 1 second
  • RSK cannot access localStorage
  • Multi-tab behavior becomes inconsistent
  • The hydration sequence creates race conditions
  • Tests should emulate browser storage

Most importantly, state coordination now relies on browser side effects and not on explicit contracts.

This violates the islands’ guarantee of isolation.

Correct approach: Event-based communication

Rather than sharing storage, islands communicate via event buses.

This keeps the islands isolated and makes coordination clear and observable.

Step 1: Create an event bus

Make public/event-bus.js:

class EventBus 
  constructor() 
    this.listeners = new Map();
  

  on(event, handler) 
    if (!this.listeners.has(event)) 
      this.listeners.set(event, new Set());
    
    this.listeners.get(event).add(handler);

    return () => 
      this.listeners.get(event).delete(handler);
    ;
  

  emit(event, payload) 
    if (!this.listeners.has(event)) return;

    for (const handler of this.listeners.get(event)) 
      handler(payload);
    
  


export const bus = new EventBus();

It defines a narrow communication channel: emit publish domain events, on subscribe to them, and the returned function allows the island to unsubscribe during unloading.

Step 2: Remove events from ProductList

Replace public/product-list.js:

import  bus  from "./event-bus.js";

const root = document.getElementById("product-island");

root.innerHTML = `
  <h2>Products</h2>
  <button data-id="1">Add Product 1</button>
  <button data-id="2">Add Product 2</button>
`;

root.addEventListener("click", (e) => 
  if (e.target.tagName === "BUTTON") 
    const id = e.target.dataset.id;
    bus.emit("cart:add",  id, quantity: 1 );
  
);

Step 3: Subscribe on CartBadge

Replace public/cart-badge.js:

import  bus  from "./event-bus.js";

const root = document.getElementById("cart-island");

root.innerHTML = `
  <h2>Cart</h2>
  <span id="count">0</span> items
`;

const countEl = document.getElementById("count");

const cartState =  items: [] ;

function render() 
  countEl.textContent = cartState.items.length;


bus.on("cart:add", (item) => 
  cartState.items.push(item);
  render();
);

render();

Badges now update immediately. There are no polls, no global storage, and no time dependency on when other islands write states.

Integrate async server updates without breaking isolation

Asynchronous logic must remain localized to the transmitter island. Consumers should rely solely on event contracts.

Update server/server.js

import express from "express";
import path from "path";
import  fileURLToPath  from "url";

const app = express();
app.use(express.json());

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

let cart = [];

app.post("/api/cart", (req, res) => 
  const  id, quantity  = req.body;
  cart.push( id, quantity );
  res.json( success: true, cartCount: cart.length );
);

app.use(express.static(path.join(__dirname, "../public")));

app.listen(3000, () => 
  console.log("Server running at 
);

Update ProductList with async handling

import  bus  from "./event-bus.js";

const root = document.getElementById("product-island");

root.innerHTML = `
  <h2>Products</h2>
  <button data-id="1">Add Product 1</button>
  <button data-id="2">Add Product 2</button>
  <div id="status"></div>
`;

const statusEl = document.getElementById("status");

root.addEventListener("click", async (e) => {
  if (e.target.tagName === "BUTTON") 
    const id = e.target.dataset.id;
    statusEl.textContent = "Adding...";

    try 
      const res = await fetch("/api/cart", 
        method: "POST",
        headers:  "Content-Type": "application/json" ,
        body: JSON.stringify( id, quantity: 1 )
      );

      const data = await res.json();
      bus.emit("cart:updated",  count: data.cartCount );
      statusEl.textContent = "Added";
     catch (err) 
      bus.emit("cart:error",  message: err.message );
      statusEl.textContent = "Failed";
    
  
});

Update CartBadge to react to async events

import  bus  from "./event-bus.js";

const root = document.getElementById("cart-island");

root.innerHTML = `
  <h2>Cart</h2>
  <span id="count">0</span> items
  <div id="error" style="color:red"></div>
`;

const countEl = document.getElementById("count");
const errorEl = document.getElementById("error");

bus.on("cart:updated", ( count ) => 
  countEl.textContent = count;
  errorEl.textContent = "";
);

bus.on("cart:error", ( message ) => 
  errorEl.textContent = message;
);

Async limits are now built in ProductList. It emits domain events only after completing a network request. CartBadge it doesn’t matter whether the state comes from memory or a server response.

Why the event-based approach wins

The event bus model transforms coordination from an implicit side effect to an explicit contract.

  • Show: No polls and fewer unnecessary updates
  • Isolation: There are no direct cross imports between islands
  • RSK Compatibility: Doesn’t rely on primitives like browsers alone localStorage
  • Testability: Events can be simulated without emulating the storage API
  • Toughness: Failure to produce explicit cart:error program

Running the example

Install dependencies and start the server:

npm install
npm start

Open http://localhost:3000. Click the product button and immediately observe the badge update.

Stop the server and trigger a request to see the error handling action.

Products In Cart Gif

Error Handling In Action

When to use each approach

local storage coordination

Use localStorage only if persistence on reload is required and SSR is not part of the architecture. Even so, prefer event-based updates with explicit persistence over polling.

Avoid localStorage as an island coordination mechanism when the UI must update immediately or when it requires deterministic behavior.

Event-driven coordination

Use event buses when islands need to remain isolated but still coordinate UI updates. This approach increases production scale because it keeps dependencies explicit, localizes asynchronous logic, and supports SSR-friendly contracts.

Conclusion

Coordination is a core architectural challenge in Island architecture.

Use localStorage as a communication channel incurs hidden coupling, polling overhead, and SSR mismatch. It seems simple but turns complexity into runtime behavior.

Event-based models maintain isolation while making coordination explicit, observable, and testable. Async logic remains localized. State transitions become domain events and not side effects.

The broader principle is simple: coordination in Island architecture should be explicit, not incidental.

You can build on this pattern by introducing typed events, schema validation for loads, or swapping in-memory buses for framework-level storage in an environment like Astro.

The post How to solve coordination problems in Islands architecture appeared first on LogRocket Blog.

PakarPBN

A Private Blog Network (PBN) is a collection of websites that are controlled by a single individual or organization and used primarily to build backlinks to a “money site” in order to influence its ranking in search engines such as Google. The core idea behind a PBN is based on the importance of backlinks in Google’s ranking algorithm. Since Google views backlinks as signals of authority and trust, some website owners attempt to artificially create these signals through a controlled network of sites.

In a typical PBN setup, the owner acquires expired or aged domains that already have existing authority, backlinks, and history. These domains are rebuilt with new content and hosted separately, often using different IP addresses, hosting providers, themes, and ownership details to make them appear unrelated. Within the content published on these sites, links are strategically placed that point to the main website the owner wants to rank higher. By doing this, the owner attempts to pass link equity (also known as “link juice”) from the PBN sites to the target website.

The purpose of a PBN is to give the impression that the target website is naturally earning links from multiple independent sources. If done effectively, this can temporarily improve keyword rankings, increase organic visibility, and drive more traffic from search results.

Jasa Backlink

Download Anime Batch