Maestro YAML File Structure: A Complete Guide to Mobile Test Flows

Maestro test flows are plain-text YAML files that declare an appId and execute a sequential list of commands parsed into YamlFluentCommand objects.

The Maestro framework by mobile-dev-inc uses these YAML files to define automated UI tests for Android and iOS applications. Each flow file describes the target application and the exact steps Maestro should execute on a device or simulator, parsed by the orchestration layer into executable commands.

Top-Level Metadata and the Document Separator

Every Maestro YAML file begins with metadata that identifies the application under test. The only mandatory field is appId, which specifies the Android package name or iOS bundle identifier.

appId: com.example.myapp
name: Optional Flow Name
---

The three hyphens (---) serve as a document separator that distinguishes metadata from the command list. Any keys in the metadata section that the parser does not recognize are silently ignored, making the header extensible for future configuration options.

Command List Structure and Syntax

After the separator, the file contains a YAML array where each element represents a single command. According to the source code in YamlFluentCommand.kt (source), commands map to specific data class properties and fall into two expression forms:

Scalar shortcuts for simple commands:

- back
- clearState
- stopApp

Maps with parameters for commands requiring arguments:

- tapOn:
    text: "Login Button"
    label: "Tap login button"
- inputText: "hello@example.com"

The YamlCommandReader (source) validates the file and converts the list of YamlFluentCommands into MaestroCommand objects by selecting the first non-null property defined in the command map.

Advanced Constructs and Control Flow

Maestro supports complex logic through nested data structures represented by auxiliary classes in the YAML module.

runFlow inlines external flow files or command lists:

- runFlow:
    file: "./subflows/login.yaml"
    env:
      USERNAME: "test@example.com"

repeat and while create loops over command sub-lists, implemented via YamlRepeatCommand.

if and when enable conditional execution using YamlCondition predicates based on platform detection or element visibility:

- if:
    platform: android
    commands:
      - tapOn: "Android-specific menu"

config sets global MaestroConfig options affecting the entire flow execution, such as default timeouts.

Error Handling and Validation

When parsing fails, YamlCommandReader catches internal FlowParseException instances and throws a user-friendly SyntaxError that includes the file path, line number, and contextual code snippet (source). This validation occurs before any commands execute on the target device.

Complete Code Examples

Minimal Flow (Hello-World)

appId: com.example.app
---
- launchApp
- tapOn: "Accept"
- inputText: "hello world"
- assertVisible:
    text: "Welcome"

This flow starts the application, taps an acceptance button, enters text, and asserts that a welcome message appears.

Advanced Flow with Sub-flow and Loop

appId: com.example.app
---
- launchApp
- setPermissions:
    permissions: ["READ_CONTACTS", "WRITE_CONTACTS"]
- repeat:
    times: 3
    commands:
      - tapOn: "Add Contact"
      - inputText:
          label: "First name"
          text: "John"
      - inputText:
          label: "Last name"
          text: "Doe"
      - tapOn: "Save"
- runFlow:
    file: "./login_flow.yaml"
    env:
      PASSWORD: "s3cr3t"

The repeat block executes its nested commands exactly three times, while runFlow injects environment variables into the external file.

Conditional Execution

appId: com.example.app
---
- if:
    visible:
      text: "Special Offer"
    commands:
      - tapOn: "Claim Offer"
- if:
    platform: ios
    commands:
      - tapOn: "iOS Settings"

Conditions evaluate before executing their inner command lists, enabling platform-specific or state-dependent test paths.

Key Source Files

Understanding the Maestro YAML file structure requires referencing these specific files in the mobile-dev-inc/Maestro repository:

Summary

  • Maestro flows require a mandatory appId in the metadata header, followed by --- separating configuration from commands.
  • Commands follow a sequential YAML array structure using either scalar shortcuts or parameterized maps.
  • The YamlFluentCommand class maps each YAML entry to typed command objects via YamlCommandReader.
  • Advanced features include runFlow for composition, repeat/while for iteration, and if/when for conditional logic.
  • Invalid syntax triggers descriptive SyntaxError messages with line numbers parsed by YamlCommandReader.

Frequently Asked Questions

What is the mandatory field in a Maestro YAML file?

The appId field is required in the top-level metadata section. It must contain the Android package name or iOS bundle identifier of the application under test. Without this field, YamlCommandReader cannot associate the test flow with a specific target app.

How does Maestro parse conditional commands in YAML?

Maestro converts conditional blocks into YamlCondition objects that wrap nested command lists. The if key accepts predicates such as platform, visible, or notVisible. If the predicate evaluates to true during execution, Maestro runs the associated commands array; otherwise, it skips the block entirely.

Can I include another flow file inside a Maestro YAML test?

Yes, using the runFlow command. This construct accepts a file parameter pointing to an external YAML path and optionally accepts an env map to inject environment variables. The parser loads and validates the referenced file recursively before converting the entire tree into MaestroCommand objects.

What happens if my Maestro YAML syntax is invalid?

YamlCommandReader catches parsing errors internally and throws a SyntaxError containing the file path, exact line number, and surrounding context snippet. This occurs during the validation phase before any UI interaction begins, preventing partial test execution against malformed flow definitions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →