Skip to content
Back to archipelago.banuacoder.com

Core Scaffolding

How to add a second app to a Flutter workspace ​

Free Reference for app_scaffold: every variable, option and package it generates. Command: archipelago generate app_scaffold

Add another app to an existing Archipelago workspace, read the generated DI and host files, and run it per flavor.

What you'll learn ​

  • Adding another app to an existing workspace
  • Understanding the generated app, DI and host files
  • Running the app per flavor
  • Knowing what the brick wires and what it leaves to you

Prerequisites ​

  • An existing Archipelago monorepo (see Monorepo Scaffolding)
  • A UI kit in packages/ and the shared packages already generated

flutter_modular_monorepo already creates your first app. Use app_scaffold for a second or later app.

Step 1: Generate the App Scaffold ​

bash
archipelago generate app_scaffold

The prompts are:

  • appName: the name of this app
  • organization: your company name
  • domain: the top-level domain, such as com or io
  • prefix: the prefix for component names

Or use a config file:

json
{
  "appName": "MyApp",
  "organization": "MyCompany",
  "domain": "com",
  "prefix": "App"
}
bash
archipelago generate app_scaffold --config scaffold_config.json

The hook finds your single *_ui_kit package in packages/ and rewrites the imports to match. It stops with an error if it finds none or more than one.

Step 2: Understand the Generated Structure ​

text
apps/my_app/
├── android/app/                 # build.gradle.kts, proguard-rules.pro, MainActivity.kt
├── ios/Runner/AppDelegate.swift
├── fastlane/                    # Appfile, Fastfile, Matchfile, Pluginfile
├── launcher/                    # App icons per flavor
├── splash/                      # Splash screen assets
├── lib/
│   ├── app.dart                 # MaterialApp.router root
│   ├── bootstrap.dart
│   ├── main.dart
│   ├── main_development.dart
│   ├── main_staging.dart
│   ├── di/injector.dart         # Composition root
│   ├── host/                    # HostAppWidget and the pre and post launch initializers
│   └── router/app_router.dart
├── integration_test/
├── test/
│   ├── architecture/feature_boundary_test.dart
│   ├── di/injector_test.dart
│   └── support/composition_root_harness.dart
├── flavorizr.yaml
└── pubspec.yaml

The hook runs flutter create in a scratch folder. It merges only the missing platform files, so the files above win. If flutter is not on your PATH, the hook prints the manual command.

Step 3: Know What the Hook Wires ​

post_gen adds the new app to:

  • the Dart workspace
  • flavors.yaml
  • the IDE run configurations
  • target_paths in build_prepare.yaml

Without the last item, build-prepare --flavor production skips the new app.

The new app has no debug tooling. Add app_debugger or app_blackbox to it by hand if you need them.

Step 4: Understand the Bootstrap ​

bootstrap.dart sets up error handling, records consent, restores the saved locale and calls initializeInjector(). It then runs HostAppWidget:

dart
runApp(HostAppWidget(
  initializerController: PreLaunchInitializerController.create(),
  builder: (context, result) => builder(result),
  loadingWidget: const _BootstrapLoadingIndicator(),
));

Pre-launch blocks the first screen. It seals the feature registry, registers routes and locks the router. Post-launch runs after the first frame. See Two-Phase Initialization.

Step 5: Run Per Flavor ​

bash
cd apps/my_app
flutter run --flavor development -t lib/main_development.dart
flutter run --flavor staging -t lib/main_staging.dart

Run the generated composition-root test to check DI:

bash
flutter test test/di/injector_test.dart

Key Customization Points ​

CustomizationWhere to Change
App icon per flavorlauncher/
Splash screensplash/ and flutter_native_splash.yaml
Blocking startup workA pre-launch initializer in lib/host/initializers/
Fastlane lanesfastlane/Fastfile
Add a featureRun its brick. It registers in lib/di/injector.dart

Next Steps ​