Skip to content

Environment & Servers

CARP apps select their environment with String.fromEnvironment (--dart-define), which is fixed at build time. DebugEnv adds a runtime override layer, persisted in SharedPreferences, so a tester can re-point the app at a different servers, change the deployment mode or debug level, and flip feature flags without rebuilding.

  1. Initialize early (debug only)

    In your debug-only setup, load persisted overrides before anything reads configuration: await DebugEnv().initialize() (optionally pass your existing SharedPreferences), then install the hook with debugLaunchOverride = DebugEnv().overrideOf.

  2. Register the arguments

    DebugEnv().registerAll([...]) tells the Environment tool which arguments exist and how to edit them.

  3. Read through the hook

    Replace String.fromEnvironment('x') reads with debugLaunchOverride?.call('x') ?? const String.fromEnvironment('x').

  4. Apply or restart

    After editing, Apply runs your onApply hook (live reconfigure) or Restart relaunches the app so the new values are read from scratch.

// In production-reachable code (BLoC, backend): read via the hook.
final mode = debugLaunchOverride?.call('deployment-mode')
?? const String.fromEnvironment('deployment-mode', defaultValue: 'production');
final timeout = int.tryParse(debugLaunchOverride?.call('api-timeout') ?? '') ?? 30;

DebugEnv reads are synchronous (usable inside constructors) once initialize() has completed, and are convenient inside debug-only code:

DebugEnv().string('deployment-mode', fallback: 'production');
DebugEnv().integer('api-timeout', fallback: 30);
DebugEnv().boolean('analytics-enabled', fallback: false);

Read the host through the hook in your CarpBackend, and expose a reconfigure() that re-points every CAWS service:

String get host {
final override = debugLaunchOverride?.call('server-host') ?? '';
return override.isNotEmpty ? override : uris[deploymentMode]!;
}
Uri get uri => Uri(scheme: 'https', host: host);
Future<void> reconfigure() async {
_readDeploymentModeDebugLevel(); // re-read launch args
await CarpAuthService().configure(authProperties);
CarpService().configure(app);
CarpParticipationService().configureFrom(CarpService());
CarpDeploymentService().configureFrom(CarpService());
CarpDataStreamService().configureFrom(CarpService());
}

Wire it up with onApply: () => bloc.backend.reconfigure().

Each registered argument is described by an EnvEntry. The type decides which editor the tool renders.

key · String · required

The --dart-define name and storage / lookup key (e.g. deployment-mode).

label · String · required

Label shown in the app page.

type · EnvValueType · default text

text, enumeration, toggle or integer.

options · List of String

Allowed values when type is enumeration (rendered as a dropdown).

fallback · String

The compile-time default, typically String.fromEnvironment(...). Shown when no override is set and used by Revert to default.

group · String

Optional heading (e.g. Server, Logging) for visual grouping.

description · String

Optional explanatory text shown under the editor.

EnvEntry(key: 'deployment-mode', label: 'Deployment mode',
type: EnvValueType.enumeration, options: ['production', 'test', 'dev'],
fallback: 'production');
DebugEnv().hasOverride('server-host'); // bool
DebugEnv().overrideOf('server-host'); // String? (raw override)
await DebugEnv().setOverride('server-host', 'dev.carp.dk');
await DebugEnv().clearOverride('server-host'); // revert to default
await DebugEnv().clearAll(); // revert everything