single-spa vs qiankun
Micro-Frontend Architecture Implementation
single-spaqiankun

Micro-Frontend Architecture Implementation

qiankun and single-spa are both JavaScript libraries designed to enable micro-frontend architectures, allowing teams to build applications composed of multiple independent fragments that can be developed, deployed, and scaled separately. single-spa is the foundational framework that provides the core routing and lifecycle management for stitching together different frameworks (React, Vue, Angular, etc.) in a single page. qiankun is built on top of single-spa and extends it with additional features focused on isolation, such as JavaScript sandboxing and CSS scoping, aiming to provide a more complete out-of-the-box solution for enterprise-grade micro-frontends.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
single-spa504,43013,8822.12 MB642 years agoMIT
qiankun77,89116,6391.66 MB4313 years agoMIT

qiankun vs single-spa: Architecture, Isolation, and Setup Compared

Both qiankun and single-spa solve the same fundamental problem: how to run multiple frontend applications within a single browser tab without them breaking each other. However, they approach this challenge with different levels of abstraction and built-in safeguards. Let's compare how they handle registration, isolation, and communication.

πŸ—οΈ Registration and Routing Setup

single-spa requires you to manually define activity functions that determine when an app should be active. You register each application individually with a name, a loading function, and a condition.

// single-spa: Manual registration with activity function
import { registerApplication, start } from 'single-spa';

registerApplication({
  name: '@myorg/app-one',
  app: () => System.import('@myorg/app-one'),
  activeWhen: (location) => location.pathname.startsWith('/app-one'),
  customProps: { store: myStore }
});

start();

qiankun simplifies this by grouping registrations into a single configuration array passed to registerMicroApps. It handles the routing logic internally based on the activeRule.

// qiankun: Batch registration with activeRule
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'app-one',
    entry: '//localhost:7100',
    container: '#container',
    activeRule: '/app-one',
    props: { store: myStore }
  }
]);

start();

πŸ›‘οΈ JavaScript Isolation: Sandboxing

single-spa does not provide JavaScript sandboxing out of the box. If two apps modify the same global variable (like window.user), they will conflict. You must rely on build tools (like Webpack Module Federation) or strict coding conventions to avoid this.

// single-spa: No built-in sandbox
// Risk: App A and App B both access window.globalConfig
window.globalConfig = { theme: 'dark' }; // App A
window.globalConfig = { theme: 'light' }; // App B overwrites it

qiankun includes a JavaScript sandbox that runs micro-apps in a Proxy-based environment. This prevents child apps from polluting the global window object, ensuring that global variables stay local to the app.

// qiankun: Proxy Sandbox enabled by default
// App A modifies window within its sandbox
window.localConfig = { theme: 'dark' }; 
// App B cannot see window.localConfig from App A
// When App A unmounts, the sandbox cleans up global side effects

🎨 CSS Isolation: Styling Boundaries

single-spa relies on CSS naming conventions (like BEM) or CSS Modules to prevent style conflicts. It does not automatically scope styles, so a global CSS reset in one app can break another.

/* single-spa: Manual scoping required */
.app-one-button { background: blue; } /* Must use unique prefixes */
.app-two-button { background: red; }

qiankun offers built-in CSS scoping. It can rewrite styles to ensure they only apply within the micro-app's container. It also supports Shadow DOM for stricter isolation, though this comes with its own trade-offs regarding event bubbling.

/* qiankun: Automatic scoping via data attributes */
/* qiankun adds data-qiankun-app-one to the container */
[data-qiankun-app-one] .button { background: blue; }
/* Styles are scoped automatically during runtime */

πŸ”„ Lifecycle Management

single-spa expects each micro-app to export specific lifecycle functions (bootstrap, mount, unmount). The framework calls these at the right times, but you must implement them in every sub-application.

// single-spa: Explicit lifecycle exports in sub-app
export async function bootstrap(props) { /* init */ }
export async function mount(props) { /* render */ }
export async function unmount(props) { /* cleanup */ }

qiankun also uses these lifecycle hooks but wraps them to handle the sandboxing and container mounting automatically. If you are using a supported framework (like Vue or React), qiankun provides helpers to reduce boilerplate.

// qiankun: Lifecycle with sandbox context
export async function render(props) {
  const { container } = props;
  // Render logic here, qiankun handles the container injection
  ReactDOM.render(<App />, container.querySelector('#root'));
}

export async function mount(props) { render(props); }
export async function unmount(props) { /* cleanup */ }

πŸ“‘ Global State Communication

single-spa does not enforce a specific way to share state between apps. Developers typically use custom events, a shared store module, or browser storage (localStorage).

// single-spa: Custom event bus pattern
window.dispatchEvent(new CustomEvent('USER_LOGIN', { detail: user }));
// Another app listens for this event

qiankun provides a built-in global state API called initGlobalState. This allows the main app and micro-apps to share reactive data without setting up external libraries.

// qiankun: Built-in global state
import { initGlobalState } from 'qiankun';

const actions = initGlobalState({ user: null });
actions.onGlobalStateChange((state) => {
  console.log('User updated:', state.user);
}, true);

🌱 When Not to Use These

These libraries are powerful but add complexity. Consider alternatives when:

  • You are building a small application – A monorepo with simple routing is easier to manage.
  • You need SEO for all sub-routes – Server-side rendering across micro-frontends is difficult to configure correctly.
  • Your team lacks DevOps maturity – Micro-frontends require independent deployment pipelines; without them, you gain no benefit.

πŸ“Œ Summary Table

Featuresingle-spaqiankun
Core BasisVanilla JS CoreBuilt on top of single-spa
JS Isolation❌ Manual (Build tools)βœ… Proxy Sandbox (Built-in)
CSS Isolation❌ Manual (Naming conventions)βœ… Automatic Scoping / Shadow DOM
RegistrationIndividual registerApplicationBatch registerMicroApps
Global State❌ Custom implementationβœ… initGlobalState API
Setup ComplexityMedium (More config)Low (More conventions)

πŸ’‘ Final Recommendation

Think in terms of isolation needs and team structure:

  • Need strict separation? β†’ Go with qiankun. The built-in sandboxing saves time and prevents hard-to-debug global conflicts.
  • Need maximum flexibility? β†’ Go with single-spa. It gives you the raw tools to build your own architecture without hidden magic.
  • Migrating a monolith? β†’ qiankun is often easier for incremental adoption because it handles more edge cases automatically.

Final Thought: Both tools enable the same architectural pattern, but qiankun acts as a batteries-included layer over single-spa. If you don't need the extra isolation features, single-spa keeps your dependency tree smaller. If you need enterprise-grade safeguards, qiankun is worth the trade-off.

How to Choose: single-spa vs qiankun

  • single-spa:

    Choose single-spa if you prefer a lightweight core that gives you full control over how isolation and routing are implemented. It is suitable for teams that want to build custom tooling around their micro-frontends or need to support legacy systems with specific constraints. This approach is best when you want to avoid the opinionated structure of qiankun and manage lifecycle methods manually.

  • qiankun:

    Choose qiankun if you need stronger isolation guarantees between micro-apps without configuring complex build pipelines. It is ideal for teams that want built-in JavaScript sandboxing and CSS scoping to prevent global variable conflicts and style leaks. This package works well for organizations migrating from a monolith to micro-frontends where apps might be written by different teams using different versions of dependencies.

README for single-spa

npm version NPM Downloads

single-spa

Join the chat on Slack

Donate to this project

Official single-spa hosting

baseplate-logo-standard

A javascript framework for front-end microservices

Build micro frontends that coexist and can (but don't need to) be written with their own framework. This allows you to:

Sponsors

DataCamp-Logo Toast-Logo asurion-logo

To add your company's logo to this section:

Documentation

You can find the single-spa documentation on the website.

Check out the Getting Started page for a quick overview.

Demo and examples

Please see the examples page on the website.

Want to help?

Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for contributing on the single-spa website.

Contributing

The main purpose of this repository is to continue to evolve single-spa, making it better and easier to use. Development of single-spa, and the single-spa ecosystem happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving single-spa.

Code of Conduct

Single-spa has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.

Contributing Guide

Read our contributing guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to single-spa.