Skip to content
Build Station

Presets

Presets are named build configurations: platform, mode, flavor, Dart defines, env and pre-steps, with a live command preview and a dry run.

A preset is a named build configuration, for example “Android – Play Store (AAB)” or “iOS – TestFlight”. A project can have as many as you like. In the Build tab you pick one, check the version and start.

You create presets in the project editor: Projekt bearbeiten (Edit project) in the Build tab, then + Preset in the Presets section. You open an existing preset there via the pencil icon, or directly in the Build tab via the edit button on the displayed command. Many presets are already created when you add the project, from the assistant’s suggestions.

The two modes

Mode What for
Flutter-Befehl (Flutter command) The command line is built from the form fields, e.g. fvm flutter build appbundle --release --flavor kundeA.
Eigenes Script (custom script) A freely defined shell script, maintained inline or as a file in the repository.

Dart defines, env, flavor, target, version and pre-steps apply in both modes. In script mode they reach the script as BS_* environment variables instead of flowing into a command line. That keeps the history comparable. Everything about script mode is in Custom scripts and web builds.

The fields

At the top of the editor are Preset-Name (preset name), ID and Plattform (platform: Android, iOS, Web, macOS or Sonstige/other). Below that you choose the mode.

In “Flutter-Befehl” mode

Field Effect
Output-Typ (output type) App Bundle (.aab), APK (.apk), IPA (.ipa), Web or macOS (.app)
Build-Mode Release, Profile or Debug
Flavor empty means: no --flavor
Target (-t) entry point, e.g. lib/main_kunde_a.dart. The detected entry points are listed in a menu.
–dart-define-from-file file with Dart defines, relative to the project
–export-options-plist IPA only, e.g. ios/ExportOptions.plist

--dart-define-from-file is the recommended way to handle secrets. The Station never reads the file, it only passes the path on. Keep the file out of the repository with .gitignore.

In both modes

Section Content
Dart-Defines Compile-time constants in the app (String.fromEnvironment). The project’s default Dart defines apply too and can be overridden here.
Env Process environment for the toolchain, such as JAVA_HOME or DEVELOPER_DIR. Doesn’t end up in the app.
Pre-Steps Steps before the build (see below)
artifactGlobs Patterns the Station uses to look for artifacts, e.g. build/app/outputs/**/*.aab
Extra-Args additional arguments for flutter build, e.g. --obfuscate (“Flutter-Befehl” mode only)

Values whose keys look like secrets (KEY, SECRET, TOKEN, PASSWORD, DSN) are shown masked. That protects against people looking over your shoulder, but it’s not encryption.

Other

  • Build-Nummer automatisch hochzählen (auto-increment build number) counts up from the last successful build of this preset, not from pubspec.yaml. If the store already has a higher number, the Station counts past it so the upload doesn’t fail at the end.
  • Timeout (Minuten) (timeout in minutes) cancels a hanging build. Empty means: no timeout.

Pre-steps

Pre-steps run before the actual build. You can choose from:

Step What it does
clean deletes build/ and .dart_tool, takes several minutes
pub get resolves dependencies according to pubspec.lock
pub upgrade raises dependencies to the latest allowed versions and rewrites pubspec.lock
build_runner generates code (freezed, json_serializable …)
pod install updates the iOS pods

The order is fixed, no matter in which order you tick the boxes:

clean → pub get → pub upgrade → build_runner → pod install

clean has to run before pub get, otherwise it throws away the dependencies that were just resolved.

pub upgrade as a permanent pre-step costs reproducibility: every build rewrites pubspec.lock and may build against different package versions. The editor points this out. For occasional updates there’s the pub upgrade button in the Build tab, see Versions and updates.

Live preview

The bottom of the editor always shows the Kommandozeile (command line) or the Script (aufgelöst) (resolved script), exactly as it would run with the current fields. Every change in the form updates the preview immediately. The copy icon puts the command on the clipboard so you can run it by hand in the terminal.

The same goes for the Build tab: under Auszuführender Befehl (command to run) or Auszuführendes Script (script to run) you see what actually runs when you click Build starten (start build).

Checks and dry run

Under Prüfung (check), the editor collects what’s wrong or noteworthy about the preset, for example:

  • an empty or duplicate ID
  • a Dart define key containing =
  • a file under --dart-define-from-file that doesn’t exist
  • an IPA preset without ExportOptions.plist (Xcode may then ask interactively)
  • an output type that doesn’t match the platform
  • pod install without an ios/ folder
  • a custom script without set -euo pipefail or without an artifact report

The Trockenlauf (dry run) button additionally checks paths and files without running anything. The result appears as a separate section in the editor: either with no blockers or with a list of what would prevent the build.

Presets for several customers

If you ship one app to several customers, each customer has its own project with its own presets. The differences are typically in flavor, target, Dart defines and store IDs. So you don’t have to create every preset by hand:

  • Duplizieren (Duplicate) in the project editor copies a preset within the project.
  • Duplizieren in the context menu of the project list copies an entire project including its presets.
  • A checked-in buildstation.json brings the presets to the next Mac, see Adding projects.

You can build all customer variants with one click via Alle in die Warteschlange … (add all to queue), described in Building and the queue.