Skip to content

Generating a Feature Module

What you'll learn

  • Creating a new feature module inside your monorepo
  • Choosing between single-package and API/Impl split patterns
  • Wiring the feature into the shell app via FeatureSDK
  • Adding routes, DI, and business logic layers

Prerequisites

Step 1: Generate the Feature

From your monorepo root, run:

bash
archipelago generate feature_monorepo_skeleton

Answer the prompts:

  • featureNamePayment (PascalCase, becomes payment in paths)
  • isSharedfalse for a self-contained feature, true if other features depend on it
  • hasBusinessLogictrue to include repos, usecases, and DI layers
  • hasLocaletrue if the feature manages its own translations

Step 2: Non-Interactive Config

json
{
  "featureName": "Payment",
  "isShared": false,
  "hasBusinessLogic": true,
  "hasLocale": true,
  "includeGenerated": false
}
bash
archipelago generate feature_monorepo_skeleton --config payment_config.json

Step 3: Single-Package Structure

When isShared: false, you get a self-contained feature:

features/
└── payment/
    ├── lib/
    │   ├── payment.dart                 # Barrel export
    │   └── src/
    │       ├── payment_sdk.dart          # FeatureSDK implementation
    │       ├── data/
    │       │   ├── datasources/
    │       │   │   ├── local/
    │       │   │   └── remote/
    │       │   ├── models/
    │       │   └── repositories/
    │       ├── di/
    │       │   ├── injector.dart
    │       │   ├── payment_global_module.dart
    │       │   └── payment_local_module.dart
    │       ├── domain/
    │       │   ├── entities/
    │       │   ├── repositories/
    │       │   └── usecases/
    │       ├── presentation/
    │       │   ├── payment_shell_page.dart
    │       │   └── ui/pages/
    │       └── router/
    │           └── payment_router.dart
    └── l10n/                            # Localization files

Step 4: API/Impl Split Pattern

Set isShared: true when the feature exposes contracts to other features (e.g., auth status checks). This generates two packages:

features/
├── payment_api/          # Contracts only (FeatureSDK, entities)
│   └── lib/src/
│       └── payment_sdk.dart
└── payment_impl/         # Full implementation
    └── lib/src/
        ├── payment_sdk_impl.dart
        ├── data/
        ├── di/
        ├── domain/
        ├── presentation/
        └── router/

Other features depend on payment_api only, never on payment_impl. The shell app wires the impl at the DI level.

Step 5: Register the Feature

The generated PaymentSdk class extends FeatureSDK and self-registers. Open it to see:

dart
class PaymentSdk extends FeatureSDK {
  @override
  Future<void> preLaunch() async {
    // Register DI modules
    PaymentGlobalModule().init();
    PaymentLocalModule().init();
  }

  @override
  List<RouteBase> get routes => PaymentRouter.routes;
}

Add it to the feature registry in the shell app's bootstrap.dart:

dart
FeatureRegistry.register(PaymentSdk());

When to Use Each Pattern

PatternUse When
Single packageFeature is self-contained, no other module needs its contracts
API/Impl splitOther features depend on this feature's types or status
No business logicPure UI feature (e.g., onboarding slides, static about page)
With localeFeature has user-facing strings that need translation

Next Steps

Built by Banua Coder