Skip to content
xcross
Documentation menu

Configuration

One optional YAML file that tells every xcross command, and every IDE run, where your tools live.

No file, nothing changes. With a file, every xcross process, including IDE-driven runs, uses your declared tools and paths.

config.yamldeclare once
Validatepaths, keys, executables
Overlaytools · env · roots
Every commandterminal + IDE

Where it lives

First hit wins:

  1. 1
    $XCROSS_CONFIGHonored even if the file doesn't exist yet.
  2. 2
    <config dir>/config.yaml
  3. 3
    <config dir>/config.yml
HostConfig dir
Windows%APPDATA%\xcross
Linux / macOS$XDG_CONFIG_HOME/xcross or ~/.config/xcross

Commands

xcross configInteractive TUI editor. Needs a TTY.
xcross config showPrint the path + normalized YAML.
xcross config validateCheck every path. Non-zero on failure.
xcross config *
 Roots │ Toolchains │ Tools │ Environment │ Setup │ Commands
 ──────────────────────────────────────────────────────────
 > darwinSdk: /opt/xcross/sdk
   flutterSdk: /opt/flutter
   javaHome: /usr/lib/jvm/temurin-21
   konanData: <unset>

 [Save] [Validate] [Discard] [Quit]
Tab←→Switch tab
↑↓Select
EnterEdit
svrqSave · Validate · Discard · Quit

Saves validate first and write atomically.

The file format

roots:
  darwinSdk: "/opt/xcross/sdk"
  flutterSdk: "/opt/flutter"          # Flutter
  javaHome: "/usr/lib/jvm/temurin-21" # Compose
  konanData: "/var/cache/konan"       # Compose
  xcross: "/usr/local/bin/xcross"
toolchains:
  swift: "/opt/swift/usr/bin"
  llvm: ["/usr/lib/llvm-19/bin"]
tools:
  flutter: "/opt/flutter/bin/flutter"
environment:
  PATH: ["/opt/swift/usr/bin"]
setup: "https://example.com/setup.sh"
excluded_commands: ["update"]

Unknown keys are hard errors (Unknown key $.roots.flutter), so typos fail fast.

roots

KeyUsed for
darwinSdkDarwin SDK bundle
flutterSdkFlutter SDK, exported as FLUTTER_ROOT
javaHomeJDK for Compose, exported as JAVA_HOME
konanDataKotlin/Native cache, exported as KONAN_DATA_DIR
xcrossLauncher used when xcross or an IDE re-invokes itself

toolchains, tools

toolchains.swift is one bin directory, toolchains.llvm one or many. They are searched before PATH. tools overrides single executables by name (Flutter.EXE = flutter), and each must exist and be executable.

tools.OpenAppleMacrosServer points xcross at your own build of the Apple macro server (SwiftUI, #Preview, FoundationModels) instead of the one bundled with the release.

environment

Allowlist only: PATH · CC · CXX · SWIFT_EXEC · SWIFT_EXEC_MANIFEST · JAVA_HOME · FLUTTER_ROOT · KONAN_DATA_DIR · LIBRARY_PATH · C_INCLUDE_PATH · CPLUS_INCLUDE_PATH. PATH entries are prepended.

setup

A local path or http(s) URL. Replaces the built-in xcross setup. Remote scripts are cached by SHA-256 and rechecked before each run.

excluded_commands

Hides commands from help, completion and dispatch. Handy for locked-down images.

Variables

$VAR, ${VAR} and ~ on POSIX, %VAR% on Windows. Recursive, cycle-checked, and undefined variables are errors.

roots:
  flutterSdk: "$HOME/sdks/flutter"

What happens at startup

Discover$XCROSS_CONFIG → config.yaml → config.yml
Parse + validateexpand variables, check every path
Apply overlaytools, env, roots, excluded commands
Run your commandchildren inherit XCROSS_CONFIG

Recipes

Complete files. Drop one in, then xcross config validate.

Pin a second LLVM without touching PATH

Your distro’s default lld is too old to link iOS, but a newer one sits beside it. Point xcross at that one only, leaving the rest of the system alone.

toolchains:
  llvm:
    - "/usr/lib/llvm-19/bin"
Use a Flutter SDK that isn't installed globally

A checkout in your home directory, not on PATH. Set the root so xcross knows the SDK layout, and the tool so it invokes the right binary.

roots:
  flutterSdk: "$HOME/sdks/flutter"
tools:
  flutter: "$HOME/sdks/flutter/bin/flutter"
Keep several Flutter versions side by side

One file per version, selected by an environment variable. Nothing is installed or symlinked, and switching is instant.

# ~/.config/xcross/flutter-3.29.yaml and flutter-3.35.yaml
XCROSS_CONFIG=~/.config/xcross/flutter-3.35.yaml xcross flutter run

Point your shell at one for the whole session:

export XCROSS_CONFIG=~/.config/xcross/flutter-3.35.yaml
Pin the whole toolchain explicitly

Nothing on PATH is trusted: every tool is named outright, so a system upgrade cannot silently swap a compiler underneath your builds. update and setup are removed because this host is provisioned elsewhere.

roots:
  darwinSdk: "/opt/xcross/xcross-darwin.artifactbundle"
  flutterSdk: "/opt/flutter"
  xcross: "/usr/local/bin/xcross"
toolchains:
  swift: "/opt/swift/usr/bin"
  llvm:
    - "/usr/lib/llvm-19/bin"
tools:
  flutter: "/opt/flutter/bin/flutter"
  swift: "/opt/swift/usr/bin/swift"
  clang: "/usr/lib/llvm-19/bin/clang"
  "clang++": "/usr/lib/llvm-19/bin/clang++"
  "llvm-ar": "/usr/lib/llvm-19/bin/llvm-ar"
  "ld64.lld": "/usr/lib/llvm-19/bin/ld64.lld"
excluded_commands:
  - "update"
  - "setup"

TipRun xcross config validate right after provisioning. It fails in a second on a bad path, instead of thirty minutes into a build.

A managed developer fleet

Hosts provision themselves from a script you control, and the self-updater is removed so the binary stays owned by your package manager. xcross setup runs the script and nothing else.

setup: "https://tools.example.com/xcross/setup.sh"
excluded_commands:
  - "update"

Roll out a new script without running it, then let hosts pick it up on their next setup:

xcross setup --refresh-script
Swift toolchain outside the system prefix

A swiftly-managed or hand-unpacked toolchain. toolchains.swift makes tool lookup prefer it, environment.PATH makes the child processes it spawns agree, and SWIFT_EXEC pins the exact compiler binary used for manifest and build invocations.

toolchains:
  swift: "$HOME/.swiftly/toolchains/6.4.0/usr/bin"
environment:
  PATH:
    - "$HOME/.swiftly/toolchains/6.4.0/usr/bin"
  SWIFT_EXEC: "$HOME/.swiftly/toolchains/6.4.0/usr/bin/swift-frontend"
Compose Multiplatform on a shared machine

A JDK that isn’t the system default, and a Kotlin/Native cache on a fast or roomy volume instead of ~/.konan. Both are exported to Gradle and the Kotlin compiler for you.

roots:
  javaHome: "/usr/lib/jvm/temurin-21"
  konanData: "/mnt/fast/konan"
Windows with a non-default install layout

Native %VAR% expansion, and Windows tool names normalize - .exe is stripped, so flutter and flutter.exe are the same key.

roots:
  flutterSdk: "C:\\src\\flutter"
  darwinSdk: "%APPDATA%\\xcross\\swift-sdks\\xcross-darwin.artifactbundle"
tools:
  flutter: "C:\\src\\flutter\\bin\\flutter.bat"
  clang: "C:\\Program Files\\LLVM\\bin\\clang.exe"
Make an IDE match your terminal exactly

Editors spawn xcross with their own, usually thinner, environment. Setting the launcher root means the DAP server, hot reload, and the Apple tool shims all re-enter the same binary with the same configuration attached - so a run from the Debug button behaves identically to one from your shell.

roots:
  xcross: "/usr/local/bin/xcross"
  flutterSdk: "$HOME/sdks/flutter"
Try a change without committing to it

XCROSS_CONFIG is honored even when the file does not exist yet, so you can branch your configuration, edit the copy in the TUI, and throw it away.

cp ~/.config/xcross/config.yaml /tmp/experiment.yaml
XCROSS_CONFIG=/tmp/experiment.yaml xcross config          # edit the copy
XCROSS_CONFIG=/tmp/experiment.yaml xcross flutter build   # try it

Troubleshooting

MessageCause
No xcross configuration found.show/validate ran in legacy mode. Create one with xcross config.
Unknown key $.<path>A typo or an unsupported key. Top-level keys are closed.
Root <name> must be an absolute pathRelative paths are never accepted.
Tool <name> is not executableThe override exists but lacks the executable bit or a Windows executable extension.
Environment variable <NAME> is not allowlistedOnly the listed variables may be exported.
Environment variable <NAME> is not definedA $VAR / %VAR% reference could not be expanded.
Environment expansion contains a cycleTwo values expand into each other.
Interactive configuration requires a TTY.Use xcross config show or validate in scripts.
ESC