> ## Documentation Index
> Fetch the complete documentation index at: https://flowdeck.studio/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD Integration

> Run FlowDeck in continuous integration and deployment pipelines

FlowDeck CLI is designed to work seamlessly in CI/CD environments like GitHub Actions, GitLab CI, CircleCI, Bitrise, and other automation platforms.

## License Configuration

In CI environments, FlowDeck validates your license through an environment variable instead of machine activation. This approach:

* Does not consume activation slots
* Works across ephemeral CI runners
* Requires no persistent storage

<Warning>
  Using your license as an environment variable does not count against your activation limit, but this functionality is restricted to **CI/CD environments only**. For local development, you must activate the license using `flowdeck license activate <key>`.
</Warning>

### Setting the License Key

Set the `FLOWDECK_LICENSE_KEY` environment variable in your CI configuration:

<CodeGroup>
  ```yaml GitHub Actions theme={null}
  env:
    FLOWDECK_LICENSE_KEY: ${{ secrets.FLOWDECK_LICENSE_KEY }}
  ```

  ```yaml GitLab CI theme={null}
  variables:
    FLOWDECK_LICENSE_KEY: $FLOWDECK_LICENSE_KEY
  ```

  ```yaml CircleCI theme={null}
  environment:
    FLOWDECK_LICENSE_KEY: $FLOWDECK_LICENSE_KEY
  ```

  ```yaml Bitrise theme={null}
  envs:
    - FLOWDECK_LICENSE_KEY: $FLOWDECK_LICENSE_KEY
  ```
</CodeGroup>

<Tip>
  Store your license key as a secret in your CI platform. Never commit license keys to version control.
</Tip>

### Supported CI Platforms

FlowDeck automatically detects these CI environments:

| Platform            | Detection Variable       |
| ------------------- | ------------------------ |
| GitHub Actions      | `GITHUB_ACTIONS`         |
| GitLab CI           | `GITLAB_CI`              |
| CircleCI            | `CIRCLECI`               |
| Jenkins             | `JENKINS_URL`            |
| Travis CI           | `TRAVIS`                 |
| Bitrise             | `BITRISE_IO`             |
| Buildkite           | `BUILDKITE`              |
| TeamCity            | `TEAMCITY_VERSION`       |
| Azure Pipelines     | `TF_BUILD`               |
| AWS CodeBuild       | `CODEBUILD_BUILD_ID`     |
| Xcode Cloud         | `XCODE_CLOUD`            |
| Codemagic           | `CODEMAGIC`              |
| Appcircle           | `APPCIRCLE`              |
| Bitbucket Pipelines | `BITBUCKET_BUILD_NUMBER` |
| Semaphore CI        | `SEMAPHORE`              |
| Drone CI            | `DRONE`                  |
| AppVeyor            | `APPVEYOR`               |

For other CI systems, set `CI=true` along with your license key.

## Installing FlowDeck in CI

### Using the Install Script

```bash theme={null}
curl -fsSL https://flowdeck.studio/install.sh | bash
```

### GitHub Actions Example

```yaml theme={null}
name: Build and Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: macos-14

    env:
      FLOWDECK_LICENSE_KEY: ${{ secrets.FLOWDECK_LICENSE_KEY }}

    steps:
      - uses: actions/checkout@v4

      - name: Install FlowDeck
        run: |
          curl -fsSL https://flowdeck.studio/install.sh | bash
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Initialize FlowDeck
        run: |
          flowdeck config set -w MyApp.xcworkspace -s MyApp -S "iPhone 16"

      - name: Build
        run: flowdeck build --verbose

      - name: Test
        run: flowdeck test --streaming
```

### Alternative: Using Config Files

```yaml theme={null}
      - name: Build
        run: flowdeck build --config .flowdeck/ci-config.json --streaming

      - name: Test
        run: flowdeck test --config .flowdeck/ci-config.json --streaming
```

## Configuration File

For reproducible CI builds, use a configuration file instead of command-line arguments:

### Create a Config File

Create `.flowdeck/ci-config.json` in your repository:

```json theme={null}
{
  "workspace": "MyApp.xcworkspace",
  "scheme": "MyApp",
  "configuration": "Release",
  "platform": "iOS",
  "version": "18.0",
  "xcodebuild": {
    "args": ["-enableCodeCoverage", "YES"],
    "env": {
      "CI": "true"
    }
  }
}
```

### Use in CI

```bash theme={null}
flowdeck build -c .flowdeck/ci-config.json --json
flowdeck test -c .flowdeck/ci-config.json --json
```

<Note>
  These CI examples use the explicit `--config` file format for one complete command invocation. That format is separate from the project settings files at `.flowdeck/config.json` and `.flowdeck/config.local.json`.
</Note>

### Config File Reference

| Field             | Type   | Required | Description                                                                    |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------ |
| `workspace`       | string | **Yes**  | Path to `.xcworkspace` or `.xcodeproj`                                         |
| `scheme`          | string | **Yes**  | Scheme name to build                                                           |
| `configuration`   | string | No       | Build configuration (`Debug`/`Release`). Default: `Debug`                      |
| `platform`        | string | No       | Target platform: `iOS`, `macOS`, `watchOS`, `tvOS`, `visionOS`                 |
| `version`         | string | No       | OS version (e.g., `18.0`). Uses latest if not specified                        |
| `simulatorUdid`   | string | No       | Specific simulator UDID                                                        |
| `derivedDataPath` | string | No       | Custom derived data path (default: `~/Library/Developer/FlowDeck/DerivedData`) |
| `xcodebuild`      | object | No       | Passthrough settings for xcodebuild                                            |
| `xcodebuild.args` | array  | No       | Arguments appended to xcodebuild                                               |
| `xcodebuild.env`  | object | No       | Environment variables for xcodebuild                                           |

<Info>
  See [Xcodebuild Arguments](/cli/xcodebuild-args) for complete passthrough options and [Configuration File](/cli/configuration-file) for all config fields.
</Info>

## Output Modes

### JSON (Default for CI)

Use `--json` for machine-readable output:

```bash theme={null}
flowdeck build --config .flowdeck/ci-config.json --json
```

This outputs NDJSON (newline-delimited JSON) events that can be parsed by CI tools:

```json theme={null}
{"type":"app_log","level":"info","message":"Build Started"}
{"type":"app_log","level":"info","message":"Resolving Packages"}
{"type":"app_log","level":"info","message":"Building"}
{"type":"result","operation":"build","success":true}
```

### Streaming (Human-Readable)

Use `--streaming` for clean, human-readable output in CI logs. This shows individual pass/fail results grouped by test class, with a summary at the end:

```bash theme={null}
flowdeck build --config .flowdeck/ci-config.json --streaming
flowdeck test --config .flowdeck/ci-config.json --streaming
```

### Parsing JSON Results

```bash theme={null}
# Check if build succeeded
flowdeck build --config .flowdeck/ci-config.json --json | \
  jq -s 'last | select(.success == true)' && echo "Build passed"

# Extract errors
flowdeck build --config .flowdeck/ci-config.json --json | \
  jq 'select(.level == "error")'
```

## Simulator Management in CI

### Boot a Specific Simulator

```bash theme={null}
# List available simulators
flowdeck simulator list -P iOS -A --json

# Boot by name
flowdeck simulator boot "iPhone 16"

# Boot by UDID (more reliable in CI)
flowdeck simulator boot "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
```

### Create a Simulator (if needed)

```bash theme={null}
flowdeck simulator create -n "CI-iPhone" --device-type "iPhone 16" --runtime "iOS 18.0"
```

## Best Practices

### 1. Use Config Set or Configuration Files

For reproducibility, either use `flowdeck config set` or config files:

```bash theme={null}
# Option 1: Save settings once
flowdeck config set -w MyApp.xcworkspace -s MyApp -S "iPhone 16"
flowdeck build --json

# Option 2: Use config file
flowdeck build -c .flowdeck/ci-config.json --json
```

### 2. Choose the Right Output Mode

Use `--json` when you need machine-readable output for parsers or dashboards. Use `--streaming` when you want clean, human-readable CI logs:

```bash theme={null}
flowdeck build --json        # Machine-readable NDJSON events
flowdeck test --streaming    # Human-readable grouped results
```

### 3. Specify Simulator by UDID

Simulator names can vary across CI runners. Use UDIDs for consistency:

```json theme={null}
{
  "workspace": "MyApp.xcworkspace",
  "scheme": "MyApp",
  "simulatorUdid": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
}
```

Or resolve dynamically:

```bash theme={null}
# Get the first available iPhone 16 simulator UDID
SIMULATOR_UDID=$(flowdeck simulator list -P iOS --json | \
  jq -r '.[] | select(.name | contains("iPhone 16")) | .udid' | head -1)

flowdeck config set -w MyApp.xcworkspace -s MyApp -S "$SIMULATOR_UDID"
flowdeck build --json
```

### 4. Clean Before Release Builds

```bash theme={null}
flowdeck clean --all
flowdeck build -c .flowdeck/release-config.json --json
```

### 5. Use Derived Data Paths

Avoid conflicts with concurrent builds:

```json theme={null}
{
  "workspace": "MyApp.xcworkspace",
  "scheme": "MyApp",
  "derivedDataPath": "/tmp/flowdeck-derived-data"
}
```

## Troubleshooting

### "License validation failed"

Ensure `FLOWDECK_LICENSE_KEY` is set correctly:

```bash theme={null}
# Check if variable is set
echo $FLOWDECK_LICENSE_KEY

# Verify CI detection
flowdeck license status
```

### "Simulator not found"

List available simulators and use exact names or UDIDs:

```bash theme={null}
flowdeck simulator list -P iOS -A --json
```

### Build Timeout

Increase timeout for large projects:

```yaml theme={null}
# GitHub Actions
- name: Build
  timeout-minutes: 30
  run: flowdeck build --config .flowdeck/ci-config.json --json
```
