Skip to content

Build Prepare

The build-prepare command swaps debug and release dependencies at build time. It performs two passes:

  1. pubspec.yaml swap — replaces debug package names with noop package names (or vice versa) in all pubspec.yaml files under target_paths
  2. Dart import rewrite — replaces package: import URIs in .dart files under lib/ and test/ inside each target_path, so host code stays valid after the package name swap

Usage

bash
# Swap to debug dependencies for development
dart run monorepo_toolkit build-prepare debug

# Swap to release (noop) dependencies for production builds
dart run monorepo_toolkit build-prepare release

# Use a custom config path
dart run monorepo_toolkit build-prepare release --config path/to/config.yaml

Configuration

Create a build_prepare.yaml at the workspace root:

yaml
build_prepare:
  mappings:
    - debug: monitoring_impl
      release: monitoring_noop

    - debug: app_launch_tracker_impl
      release: app_launch_tracker_noop

  target_paths:
    - apps/template_app

Configuration fields

FieldRequiredDescription
mappings[].debugYesThe debug/development package name (e.g., monitoring_impl)
mappings[].releaseYesThe release/noop package name (e.g., monitoring_noop)
target_pathsNoDirectories to scan. If empty, scans all workspace packages (pubspec swap only; no import rewrite)

How it works

Pass 1 — pubspec.yaml swap

Every occurrence of the debug package name is replaced with the release package name in pubspec.yaml (and vice versa for debug mode). This covers both the dependency key and the path: reference.

Debug mode (pubspec.yaml after build-prepare debug):

yaml
dependencies:
  app_launch_tracker_impl:
    path: ../../infrastructure/app_launch_tracker_impl

Release mode (pubspec.yaml after build-prepare release):

yaml
dependencies:
  app_launch_tracker_noop:
    path: ../../infrastructure/app_launch_tracker_noop

Pass 2 — Dart import rewrite

After the pubspec swap, build-prepare walks every .dart file under lib/ and test/ inside each target_path and rewrites two patterns:

  • package:<debug_pkg>/package:<release_pkg>/ (all import paths)
  • /<debug_pkg>.dart/<release_pkg>.dart (barrel file references)

Example — an import in apps/template_app/lib/di/injector.dart:

dart
// Before (debug):
import 'package:app_launch_tracker_impl/app_launch_tracker_impl.dart';

// After build-prepare release:
import 'package:app_launch_tracker_noop/app_launch_tracker_noop.dart';

The rewrite is reversible: build-prepare debug swaps the names back, restoring the original imports exactly.

Why import rewrite is required

build_prepare never rewrites class names — only import paths. This means both the debug impl and the release noop must export a class of the same name. When app_launch_tracker_impl is swapped out for app_launch_tracker_noop, AppLaunchTracker is still the class name in both packages. The only thing that changes is the import path, which build-prepare handles automatically.

This is the unified-class-name Impl/Noop pattern — see the architecture guide for when to use it.

Melos shortcuts

bash
melos run build-prepare:debug    # Swap to debug dependencies
melos run build-prepare:release  # Swap to release (noop) dependencies

Fastlane integration

The template's Fastfile calls build-prepare automatically:

ruby
before_all do
  sh("dart run monorepo_toolkit build-prepare release")
end

after_all do
  sh("dart run monorepo_toolkit build-prepare debug")
end

Always restore debug dependencies after the build, even if the build fails.

CI integration

yaml
steps:
  - name: Prepare release deps
    run: dart run monorepo_toolkit build-prepare release

  - name: Build release
    run: flutter build appbundle --flavor production

  - name: Restore debug deps
    if: always()
    run: dart run monorepo_toolkit build-prepare debug

When to use this

Use build-prepare for packages that:

  • Have a debug implementation with vendor SDKs or profiling overhead
  • Should be completely absent from release builds (not just disabled at runtime)
  • Follow the Impl/Noop pattern with unified class names (no _api contract needed)

The monitoring_impl / monitoring_noop pair is the canonical API/Impl/Noop example (both implement AppMonitoring from monitoring_api). The app_launch_tracker_impl / app_launch_tracker_noop pair is the canonical Impl/Noop without _api example — both export class AppLaunchTracker with identical method signatures, so no shared interface package is needed.

Built by Banua Coder