FC 0007 - Piral and single-spa feature comparison










Layout Engine / Common Navigation

Piral Layout is accomplished via react components. Layout is just a component that can contain other components. The Root DOM is controlled by the container app, and each pilet will render inside a layout component defined in that DOM. Pilets can futher delegate rendering of portions of their DOM to other pilets. Piral has built in layout components for menus, notifications, modals, dashboards etc...

Layout can be done manually in the root-config via registerApplication API, or by using the optional layout engine. single-spa Layout is intended only for top level HTML elements, Routes, and MFE top level invocation. It can provide routing between MFEs, common views and error hadlers,etc. MFEs are responsible for their own layout AND internal routing using JS Frameworks (or by using a custom utility module for shared layout)


Common User Experience

UX components and styles can be published via pilet for use by other pilets

Utility Microfront ends are designed for sharing common logic and sevices. Qiankun has support


Common UI Components

UX components and styles can be published via pilet for use by other pilets

Utility Microfront ends are designed for sharing common logic and sevices. Qiankun has support


Delegated Runtime configurations (eg: i18n, mobile, etc...)

non rendering pilets can be injected by domain app during runtime

Utility Microfront ends are designed for sharing common logic and sevices. Qiankun has support










Container Services specification and lifecyle

Piral App generates a library module that MFE's declare as dependencies. MFEs must exposed a "setup" method that receives the Pilet API. Piral manages the lifecycle from there.

MFE's are independent and only rely on container lifecycle events and import maps. They do not use shared libraries like Piral. MFEs must implement the single-spa lifecycle event handlers: bootstrap, mount, unmount, and unload(optional). MFE to MFE or MFE to Container interactions can be done through the single-spa API.


  • MFE Loading and Unloading / Server Side Rendering

Pilets resources can be lazyloaded via react, or composed server side and hydrated on the client. Pilets themselves are either dynamically loaded from a pilet service, or statically defined in a json file and loading is opaquely handled. In a SSR, pilets are retrieved by an auxiliary library, rendered on the server, then hydreated server side.

MFE's are loaded via import maps. MFE resources are loaded according to their own framework rules. In a SSR, MFEs are retrieved either by Module Loading (import() and faciliated by import maps) or by http request (requires a webserver for each MFE), rendered on the server, then hydrated server side.


  • MFE Lifecyle (initilization, unloading)

A single lifecycle setup() function receives the pilet Api. Api contains common methods to register and unregister pages, components, extensions etc... as well as custom container specific methods (eg to support edX domains)

MFEs must implement 3 required and 1 optional lifecycle methods. The single-spa API, as well as custom properties from the container are exposed to MFEs via these lifecycle interfaces.


  • Runtime services: dependency sharing and mgmt

Declaratively via importMaps. Programatically from the Piral container. Pillets can also share dependencies

Declaratively via import map provided through System JS polyfills


  • Runtime services: shared APIs

Common Piral api shared from Piral container. API can be extended with custom methods

Common API shared by single-spa. Custom API’s must be provided by MFEs


  • Runtime services: events

Common event back end shared by Piral container and all pilets.

Common event back end shared via single-spa API


  • Runtime services: Error Handling

Layout manager offers global error handler

Errors are defined and extended via the single-spa API. Layout Engine (optional) provides global routes


  • Runtime services: Shared Dependencies (React, Paragon)

Multiple extensions to support this (pilet API, import maps, imperative sharing via api)

Done via import maps in root-config


  • Runtime services: Routing

Piral app provides routing via react for both inter and intra pilet routing

single-spa is responsible for routing between MFEs. Routing inside MFEs is framework dependent (React, Angular etc...)


  • Runtime services: Global shared state

built in GlobalSharedState react hook in the Piral api.

ALL these are generally outside the scope of single-spa. community supported libraries and a set of recommended best practices would need to be explored and determinations made on the best way to integrate support for these features.

Qiankun is a library that implements these services on top of single spa and has extensive documentation. The project is


  • Runtime services: authentication

Authentication plugins are provided for common schemes. Custom schemes can be easily integrated like in any React app.


  • Runtime services: messages

support for custom "actions" which are then implemented as hooks


Network Performance (artifact size, artifact type - npm / MFE, CDN)

Pilet Feed Service is an runtime service that provides runtime loading configuration for pilets. IT can be replaced by a static definition in the Piral container.

MFEs use a common webpack configuration provided by the container to optimize network usage


Server side MFEs

Supported. Helper library provided with built in functions for fetching pillets, composing and rendering the DOM and then client side React support for hydrating

Supported. Helper library provided to assist with fetch, composition, rendering and hydration


Project Maturity








DevStack integration and tooling

Piral CLI for quick setups. Offline support. Backend mock support via KRAS. Piral and other MFEs are encapsulated via NPM. MUUUUUUCH simpler front end builds

CLI for scripting quick setups


Multi-repo vs Single-repo

Either supported

Either supported


Developer efficiency

Top priority for the Piral architecture

Framework is not opinionated. Developer support mostly provided through community.