DEV Community

MAYANK TYAGI
MAYANK TYAGI

Posted on

Building a Scalable React Native Super App with Re.Pack & Module Federation

Building a Super App with React Native: Lessons Learned

In the past few years, super apps have become a popular approach for enterprises that want to bring multiple services under one umbrella. Instead of forcing users to download and maintain multiple apps, a super app provides a single entry point where mini-apps or feature modules can live together.

When my team started building an enterprise super app with React Native, our goal was simple:

  • Make it scalable so new modules can be plugged in easily.
  • Ensure it works even in offline environments (like warehouses or remote sites).
  • Keep the developer experience smooth so teams can work in parallel.

This blog shares our journey, the challenges we faced, and the architectural choices we made to make it all work.

Why React Native for a Super App?

There are plenty of options out there, but React Native stood out for us because:

  • Cross-platform support: One codebase for iOS and Android.
  • Rich ecosystem: Mature libraries for navigation, state management, and networking.
  • OTA (over-the-air) updates: Ability to push updates without waiting for app store approvals.
  • Community and tooling: Strong developer community and solutions like Repack for modular bundling.

Offline Mode: Prefetch and Launch Strategy

Offline mode was critical for us. Here’s how we approached it:

  1. Prefetching bundles
  • When online, the app downloads the required bundles and caches them locally.
  1. Bundle config storage
  • Metadata about which bundles are available and their versions is stored locally.
  1. Offline launch flow
  • On launch, if the device is offline, the app checks local bundle configs.
  • A popup informs the user they’re in offline mode.
  • The user is asked for their EMP ID to continue with cached features.
  1. Sync on reconnect
  • Once the device is back online, updated bundles are downloaded and old ones replaced.

This ensured users could continue working seamlessly without connectivity issues.

In this post, we’ll dive into how to design and implement a React Native Super App using Re.Pack’s Module Federation, covering:

  • βš™οΈ Architecture overview (Host, Auth, Platform, MicroApps)
  • 🧩 Dynamic loading via Federated.createURLResolver + Federated.importModule
  • πŸ“¦ Offline mode and bundle caching
  • πŸ” Authentication + federation of login flows
  • πŸš€ Real-world patterns and setup code

πŸ—οΈ High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Host App           β”‚
β”‚  ─ Auth Federation         β”‚
β”‚  ─ Bundle Fetch/Cache      β”‚
β”‚  ─ Offline Manager         β”‚
β”‚  ─ Navigation Shell        β”‚
β”‚  ─ Re.Pack Federation Init β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Auth App        β”‚     Platform App     β”‚
β”‚ - Authentication      β”‚ - Shared Services    β”‚
β”‚ - Offline Login Cache β”‚ - Reusable Hooks     β”‚
β”‚ - Token Federation    β”‚ - Realm/DB, APIs     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                       β”‚
           β–Ό                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚        Remote Micro Apps (fetched OTA)          β”‚
β”‚ ─ Dashboard, MicroApp1, MicroApp2, MicroApp3…   β”‚
β”‚ ─ Fetched via federation fetch β†’ cached offline β”‚
β”‚ ─ Access shared platform services               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Bundling Strategy

Bundled Inside the APK/IPA

These modules are packaged within the native binary:

  • Host App β†’ Shell that initializes Re.Pack federation, manages navigation, caching, and authentication state.
  • Auth App β†’ Handles authentication, MFA, and stores offline user tokens or IDs.
  • Platform Module β†’ Contains all reusable SDKs, services, DB schema, APIs, and utilities accessible by other micro apps.

Remote (Federated) Bundles

Fetched and loaded dynamically at runtime:

  • Dashboard, MicroApp1, MicroApp2, MicroApp3, etc.

Each remote bundle can be versioned and updated independently β€” no full app store deployment required.


πŸ”© Setting Up Module Federation with Re.Pack

1. Host (Shell) Configuration

// host/webpack.config.js
const { withRepack } = require('@callstack/repack');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = withRepack({
  name: 'host',
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        authApp: 'authApp',
        platform: 'platform',
        dashboard: 'dashboard',
      },
      shared: {
        react: { singleton: true, eager: true },
        'react-native': { singleton: true, eager: true },
      },
    }),
  ],
});
Enter fullscreen mode Exit fullscreen mode

2. Remote Micro App Configuration

Each micro app exposes its entry point:

// microApp1/webpack.config.js
const { withRepack } = require('@callstack/repack');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = withRepack({
  name: 'microApp1',
  exposes: {
    './Entry': './src/Entry',
  },
  shared: {
    react: { singleton: true },
    'react-native': { singleton: true },
  },
});
Enter fullscreen mode Exit fullscreen mode

🌐 Dynamic Federation Setup (Host Side)

Registering the Federation Resolver

// host/src/federationSetup.js
import { Federated, ScriptManager } from '@callstack/repack/client';
import AsyncStorage from '@react-native-async-storage/async-storage';
import RNFetchBlob from 'rn-fetch-blob';

export async function initFederation() {
  // Step 1: Fetch remote configuration from CDN
  const remoteConfig = await fetch('https://cdn.example.com/superapp/config.json').then(r => r.json());

  // Step 2: Cache remote bundles for offline usage
  for (const [name, app] of Object.entries(remoteConfig.microApps)) {
    const path = `${RNFetchBlob.fs.dirs.DocumentDir}/${name}.bundle`;
    const exists = await RNFetchBlob.fs.exists(path);

    if (!exists) {
      const data = await fetch(app.url).then(r => r.text());
      await RNFetchBlob.fs.writeFile(path, data, 'utf8');
    }

    // Save local mapping
    app.localPath = path;
  }

  // Step 3: Persist config
  await AsyncStorage.setItem('remoteConfig', JSON.stringify(remoteConfig));

  // Step 4: Register resolver for both online/offline cases
  const resolver = Federated.createURLResolver(name => {
    const config = remoteConfig.microApps[name];
    return config?.localPath || config?.url;
  });

  ScriptManager.addResolver(resolver);
}
Enter fullscreen mode Exit fullscreen mode

🧠 Auth App β€” Federated Authentication & Offline Login

Federated Exposure

// authApp/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'authApp',
      exposes: {
        './AuthModule': './src/AuthModule',
      },
      shared: ['react', 'react-native'],
    }),
  ],
};
Enter fullscreen mode Exit fullscreen mode

Offline-Aware Auth Module

// authApp/src/AuthModule.js
import AsyncStorage from '@react-native-async-storage/async-storage';

export async function loginUser(username, password) {
  try {
    const token = await authenticateOnline(username, password);
    await AsyncStorage.setItem('userToken', token);
    return { status: 'online', token };
  } catch (e) {
    // Fallback to offline mode if token exists
    const cachedToken = await AsyncStorage.getItem('userToken');
    if (cachedToken) return { status: 'offline', token: cachedToken };
    throw new Error('Offline and no cached credentials');
  }
}
Enter fullscreen mode Exit fullscreen mode

The Auth App can be used by the Host or any MicroApp via federation import:

const { loginUser } = await Federated.importModule({
  scope: 'authApp',
  module: './AuthModule',
});
Enter fullscreen mode Exit fullscreen mode

🧩 Platform Module β€” Shared Services & SDKs

The Platform Module acts as a shared layer between micro apps and the host β€” containing reusable pieces like:

  • Database (Realm / SQLite)
  • Shared hooks and API clients
  • Theme, constants, and feature flags
  • Utility SDKs (network, analytics, etc.)

It’s federated like any other app but bundled with the host to ensure availability.

// platform/src/api/index.js
export const fetchWithAuth = async (url, options = {}) => {
  const token = await AsyncStorage.getItem('userToken');
  return fetch(url, { ...options, headers: { Authorization: `Bearer ${token}` } });
};
Enter fullscreen mode Exit fullscreen mode

Then imported dynamically in any micro app:

const { fetchWithAuth } = await Federated.importModule({
  scope: 'platform',
  module: './api/index',
});
Enter fullscreen mode Exit fullscreen mode

πŸ“± Loading a Remote Micro App (e.g. Dashboard)

// host/src/loadMicroApp.js
import React from 'react';
import { Federated } from '@callstack/repack/client';

export async function loadMicroApp(name) {
  const mod = await Federated.importModule({
    scope: name,
    module: './Entry',
  });
  return mod.default;
}

// usage
const Dashboard = React.lazy(() => loadMicroApp('dashboard'));
Enter fullscreen mode Exit fullscreen mode

🧭 Example Use Cases

Use Case Module Description
User login & offline access Auth App Authenticates online; caches token locally for offline use
Shared DB / APIs Platform Provides shared database layer and network SDKs
Feature dashboards Remote (Dashboard) Fetched dynamically, can be updated independently
Offline app launch Host Prefetches and loads cached bundles using Federated.createURLResolver
Hot updates Host + CDN Fetches updated remote bundles and refreshes federation config

πŸ”„ Offline Lifecycle Summary

  1. On app start, Host fetches remote config β†’ caches bundles.
  2. On next launch (offline):
  • Host loads bundles from local filesystem.
  • Auth module validates cached ID/token.
  • Micro apps mount normally using local bundles.

    1. On reconnect:
  • Host syncs new config and updates local caches.


βœ… Advantages of This Architecture

  • Independent deployments: each micro app is independently deployable & versioned.
  • Reduced release risk: update micro apps without touching host binary.
  • Offline-first: all modules can operate offline with cached bundles.
  • Federated authentication: common login/token logic shared across micro apps.
  • Code reusability: platform module enables shared SDKs across all apps.
  • Better scalability: multiple teams can work on different modules without collisions.

Developer Experience

  • Independent bundles: Teams owned their modules β†’ faster parallel development.
  • Easy onboarding: Devs could run only their bundle locally.
  • Debugging tools: With Repack’s dev server, we could inspect bundles and hot-reload features independently.

Lessons Learned

  • Keep the base shell app minimal β€” just infra, no business logic.
  • Offline mode must be designed from the start (syncing is hard to retrofit).
  • Bundle versioning is non-negotiable β€” always know what version the user is running.
  • Minimize cross-bundle dependencies β†’ treat modules like micro frontends.

πŸš€ Conclusion

This architecture brings the flexibility of web micro-frontends to React Native, powered by Re.Pack’s Module Federation.

By combining:

  • a Host for bundle management + offline logic,
  • an Auth app for federated login and offline identity,
  • a Platform module for shared services,
  • and remote micro apps fetched dynamically,

…we achieve a scalable, modular super app architecture β€” production-ready, OTA updatable, and optimized for offline environments.

If you’re planning to build a super app, start small: get your shell + bundle loader right, plan for offline, and keep your modules decoupled. Everything else will follow.


Top comments (0)