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
archipelago generate app_scaffoldThe prompts are:
- appName: the name of this app
- organization: your company name
- domain: the top-level domain, such as
comorio - prefix: the prefix for component names
Or use a config file:
{
"appName": "MyApp",
"organization": "MyCompany",
"domain": "com",
"prefix": "App"
}archipelago generate app_scaffold --config scaffold_config.jsonThe 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
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.yamlThe 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_pathsinbuild_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:
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
cd apps/my_app
flutter run --flavor development -t lib/main_development.dart
flutter run --flavor staging -t lib/main_staging.dartRun the generated composition-root test to check DI:
flutter test test/di/injector_test.dartKey Customization Points
| Customization | Where to Change |
|---|---|
| App icon per flavor | launcher/ |
| Splash screen | splash/ and flutter_native_splash.yaml |
| Blocking startup work | A pre-launch initializer in lib/host/initializers/ |
| Fastlane lanes | fastlane/Fastfile |
| Add a feature | Run its brick. It registers in lib/di/injector.dart |
Next Steps
- Set up the Network SDK for API communication
- Set up authentication to add login flows
- Generate a UI Kit to theme the app