Configuration Reference
Every key in Shipfile.yml, with defaults and examples.
On this page
Shipfile.yml is only the default config filename. ShipIt reads ./Shipfile.yml when --shipfile is omitted, but any YAML file path works with --shipfile <path>.
For config-backed CLI commands, the selected file must exist. A missing ./Shipfile.yml or missing --shipfile <path> target causes the command to exit with code 2.
Priority Order
CLI flags > SHIPIT_* env vars > .env file > config file > Built-in defaults
.env file auto-loading
ShipIt automatically loads a .env file from the same directory as Shipfile.yml before resolving configuration. Variables already in the process environment take precedence and are never overwritten.
Supported formats: KEY=VALUE, export KEY=VALUE, quoted values, and # comments. Use shipit generate to create a pre-populated .env file; it is automatically added to .gitignore.
Environment variable naming convention
Shipfile YAML keys map to env vars by upper-casing and joining path segments with _, prefixed with SHIPIT_. Nested keys use __ (double-underscore) as the section separator.
| Shipfile key | Environment variable |
|---|---|
app.scheme | SHIPIT_APP__SCHEME |
app.bundle_id | SHIPIT_APP__BUNDLE_ID |
app.team_id | SHIPIT_APP__TEAM_ID |
app_store_connect.key_id | SHIPIT_APP_STORE_CONNECT__KEY_ID |
app_store_connect.issuer_id | SHIPIT_APP_STORE_CONNECT__ISSUER_ID |
build.configuration | SHIPIT_BUILD__CONFIGURATION |
archive.export_method | SHIPIT_ARCHIVE__EXPORT_METHOD |
code_signing.git_url | SHIPIT_CODE_SIGNING__GIT_URL |
Secrets bypass: ASC_KEY_ID, ASC_ISSUER_ID, ASC_PRIVATE_KEY, ASC_PRIVATE_KEY_PATH, and VAULT_PASSWORD are also read directly (without the SHIPIT_ prefix) for compatibility with standard CI secret naming.
Top-Level Structure
platform:
app:
app_store_connect:
code_signing:
build:
archive:
export:
testflight:
screenshots:
metadata:
versioning:
project_generation:
notifications:
workflows:
custom_actions:
# Platform-specific overrides (merged on top of shared config)
ios:
android:app
| Key | Type | Description |
|---|---|---|
workspace | string | Path to .xcworkspace |
project | string | Path to .xcodeproj (used when workspace is nil) |
scheme | string | Xcode scheme for build and test |
bundle_id | string | App bundle identifier. Optional if it can be inferred from Xcode build settings |
team_id | string | Apple Developer Team ID. Optional if it can be inferred from Xcode build settings |
Where to find these values manually:
bundle_id: your target's bundle identifier / application ID in Xcode Signing settings orPRODUCT_BUNDLE_IDENTIFIERin build settingsteam_id: the 10-character Apple Developer Team ID for the team selected in Xcode Signing, also shown in the Apple Developer account / Certificates, IDs & Profiles
app_store_connect
For App Store Connect API actions, provide key_id, issuer_id, and exactly one private key source: private_key or key_path.
issuer_id is not inside the .p8 file. Copy it from the App Store Connect API Keys page.
You can omit this whole section if you only use local Xcode actions such as build, test, archive, or export.
Find these values in App Store Connect:
- Open
Users and Access. - Open
Integrations. - Open
App Store Connect API. - Create or select an API key.
- Copy
Key IDandIssuer ID. - Download the
.p8file and use it viaprivate_keyorkey_path.
If ShipIt cannot infer app.team_id, use the team selected in Xcode for the app target. The value you need is the Apple Developer Team ID, not the App Store Connect issuer ID.
| Key | Type | Env Var | Description |
|---|---|---|---|
key_id | string | ASC_KEY_ID | API key ID |
issuer_id | string | ASC_ISSUER_ID | Issuer ID |
key_path | string | — | Path to .p8 key file |
private_key | string | ASC_PRIVATE_KEY | Raw .p8 contents |
code_signing
| Key | Type | Default | Description |
|---|---|---|---|
type | string | vault | automatic, vault, or manual |
storage | string | git | git, s3, or gcs |
git_url | string | — | URL of the certificate repo |
app_identifier | string | — | Bundle ID for matching |
profile_type | string | — | appstore, adhoc, development |
p12_path | string | — | Local .p12 certificate path (manual signing) |
p12_base64 | string | — | Base64-encoded .p12 for CI / manual signing |
p12_password | string | — | .p12 certificate password |
provisioning_profile_path | string | — | Local .mobileprovision path (manual signing) |
provisioning_profile_base64 | string | — | Base64-encoded .mobileprovision for CI / manual signing |
Set VAULT_PASSWORD env var for the encrypted repo passphrase.
With type: automatic, ShipIt passes -allowProvisioningUpdates to Xcode build/export operations and writes signingStyle=automatic into export options.
With type: manual, shipit sign sync installs the configured .p12 certificate and provisioning profile. Local paths are preferred when they exist; base64 values are used as a CI fallback.
build
| Key | Type | Default | Description |
|---|---|---|---|
configuration | string | Release | Build configuration |
derived_data_path | string | — | Custom derived data path |
xcargs | map | {} | Extra flags for xcodebuild |
archive
Top-level archive keys apply to iOS archives. Android archive options are set per workflow step (see archive action options).
| Key | Type | Default | Description |
|---|---|---|---|
export_method | string | app-store | app-store, ad-hoc, enterprise, development |
include_symbols | bool | true | Include dSYMs |
include_bitcode | bool | — | Include bitcode (deprecated Xcode 14+) |
output_path | string | — | Output path for .xcarchive |
export
| Key | Type | Description |
|---|---|---|
archive_path | string | Path to .xcarchive |
output_directory | string | Output directory for IPA |
testflight
| Key | Type | Default | Description |
|---|---|---|---|
skip_waiting_for_build_processing | bool | false | Skip Apple's processing wait |
distribute_external | bool | false | Distribute to external testers |
groups | list | [] | Beta group names |
changelog | string | — | Release notes |
screenshots
| Key | Type | Default | Description |
|---|---|---|---|
devices | list | [] | Simulator device names |
locales | list | [en-US] | Locale identifiers |
scheme | string | — | Screenshot UI test scheme |
output_directory | string | ./screenshots | Output directory |
metadata
| Key | Type | Default | Description |
|---|---|---|---|
directory | string | ./metadata | Metadata directory |
submit_for_review | bool | false | Submit for review |
automatic_release | bool | false | Auto-release after approval |
phased_release | bool | false | Phased release |
versioning
ShipItSwifty follows Apple's two-version model:
| Plist key | Format | Meaning |
|---|---|---|
CFBundleShortVersionString | MAJOR.MINOR.PATCH | User-facing marketing version (e.g. 2.4.1). Bumped manually for releases. |
CFBundleVersion | plain integer | Internal build number (e.g. 317). Auto-incremented on every beta run. |
The versioning section controls how CFBundleVersion is incremented. CFBundleShortVersionString is only changed when the version action is called with bump: major, bump: minor, or bump: patch.
| Key | Type | Default | Description |
|---|---|---|---|
strategy | string | sequential | sequential — adds 1 each run (guarantees a plain integer). timestamp — uses YYYYMMDDHHmm format. |
source | string | xcodeproj | xcodeproj — reads MARKETING_VERSION/CURRENT_PROJECT_VERSION from xcodebuild -showBuildSettings; falls back to agvtool, then plutil on Info.plist. asc — reads current build number from App Store Connect. project_spec — reads/writes version values in a YAML spec file (XcodeGen/Tuist). kmp — reads/writes versionName/versionCode in gradle.properties. gradle — reads/writes directly in build.gradle.kts or build.gradle; default for Android projects. |
spec_path | string | — | Path to the project spec file (used with source: project_spec). |
build_key | string | — | YAML key path for the build number in the spec file (e.g. settings.CURRENT_PROJECT_VERSION). |
marketing_key | string | — | YAML key path for the marketing version in the spec file (e.g. settings.MARKETING_VERSION). |
version action options
The version action accepts a bump option that selects which counter to change:
bump value | Changes | Leaves untouched |
|---|---|---|
build | CFBundleVersion (integer) | CFBundleShortVersionString |
patch | Patch segment of CFBundleShortVersionString; resets CFBundleVersion to 1 | Major and minor segments |
minor | Minor segment; resets patch and CFBundleVersion to 1 | Major segment |
major | Major segment; resets minor, patch, and CFBundleVersion to 1 | — |
Version dry-run preview
Use --dry-run to see the computed before/after version values without writing anything:
shipit version --bump build --dry-run
shipit version --bump patch --dry-run --output jsonSafe bump ordering
When a workflow bumps the marketing version (patch/minor/major) and the build number in the same run, place the marketing version bump first. A marketing version bump resets the build number to 1, so running it after a build bump would discard the incremented value. Pair each version step with an immediate git commit so a late-stage failure leaves a clean rollback target.
workflows:
beta:
- action: test
- action: archive
- action: version # bump only after build succeeds
options: { bump: build }
- action: git # commit immediately so git is the rollback mechanism
options:
operation: commit # stages all changes (git add -A) then commits
commit_message: "chore: bump build number [skip ci]"
- action: export
- action: testflightThe
gitaction'soperation: commitstages every change in the working tree (git add -A) before committing — there is no per-file option. In CI this is usually what you want, since the runner starts from a clean checkout and the only modified files are the version bump. If you have unrelated local changes, commit or stash them first.
Beta workflow pattern (local-only, Apple semantics)
For a local beta that increments the build number, runs tests, then archives and exports:
versioning:
strategy: sequential # CFBundleVersion stays a plain integer
source: xcodeproj # reads/writes MARKETING_VERSION + CURRENT_PROJECT_VERSION in .xcodeproj
workflows:
beta:
- action: version
options:
bump: build # increments CFBundleVersion only; marketing version unchanged
- action: test
options:
destinations:
- "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2"
retry_on_failure: true # retry each failing test once before surfacing a failure
# only_testing: # narrow to specific targets, e.g. [NovalingoTests/CoreTests]
# skip_testing: # skip slow targets, e.g. [NovalingoUITests]
- action: archive
- action: export # exports IPA locally; no upload to App Store ConnectUse xcodebuild -showdestinations -scheme <Scheme> (or shipit ai-session --goal local) to
discover destination strings that are valid on your machine before filling in the destinations array.
You can list multiple destinations to run tests on several simulators or devices in one step.
How source: xcodeproj is resolved:
xcodebuild -showBuildSettings— readsMARKETING_VERSIONandCURRENT_PROJECT_VERSIONdirectly from Xcode build settings. This is the primary path for modern Xcode projects.xcrun agvtool— fallback for projects that haveVERSIONING_SYSTEM = apple-genericbut not the newerMARKETING_VERSIONkey.plutilonInfo.plist— last resort for legacy projects.
To add a TestFlight upload later, append a testflight step and uncomment the app_store_connect section.
test action options
The test action is configured inline in a workflow step. It does not have a top-level Shipfile section.
retry_on_failure, rerun_failed_tests, and infrastructure_retry solve different problems. Use retry_on_failure for xcodebuild's built-in one-pass iOS retry behavior. Use rerun_failed_tests when you want ShipIt to collect the initial failures, rerun those specific tests once, and emit flaky/persistent failure information in TestRunReport. Use infrastructure_retry for whole-run failures such as simulator launch crashes, Android emulator disconnects, Flutter tool crashes, or JS worker failures.
shipit generate asks whether generated test steps should enable infrastructure_retry. shipit ai-session includes the same guidance in the agent prompt so AI-assisted workflow creation asks the same question.
| Option | Type | Default | Description |
|---|---|---|---|
destinations | list | — | Required. One or more xcodebuild destination strings. Each entry triggers a separate xcodebuild test pass; pass/fail/skip counts are aggregated. Discover valid values with xcodebuild -showdestinations -scheme <Scheme>. |
destination | string | — | Legacy single-destination string. Promoted to a one-element destinations list internally. Prefer destinations for new configuration. |
scheme | string | app.scheme | Xcode scheme containing the test targets. Falls back to app.scheme when omitted. |
configuration | string | Debug | Build configuration used for test compilation. |
enable_code_coverage | bool | — | Enable -enableCodeCoverage YES. When true and result_bundle_path is unset, a path of ./build/<scheme>-tests.xcresult is auto-derived. |
result_bundle_path | string | — | Output path for the .xcresult bundle. Auto-derived when enable_code_coverage is true. |
test_plan | string | — | Named .xctestplan to run. |
only_testing | list | — | Restrict to specific targets or test cases. Each entry maps to -only-testing. |
skip_testing | list | — | Skip specific targets or test cases. Each entry maps to -skip-testing. |
retry_on_failure | bool | false | Pass -retry-tests-on-failure to retry each failing test once. |
rerun_failed_tests | object | — | Selectively rerun only the failed tests when the runner supports it. Supports enabled and max_attempts (default 2). |
report_path | string | — | Optional path to write the structured JSON TestRunReport for CI artifact upload. |
infrastructure_retry | object | — | Retry the entire test invocation for transient infrastructure failures (iOS simulator crashes, Android emulator disconnects, Flutter tool crashes, JS worker failures). Presence of this block enables retries; omit to disable. Recommended default: { max_attempts: 3, initial_delay_seconds: 2, max_delay_seconds: 30 }. |
module | string | android.module | Android/KMP. Gradle module whose tests should run. |
kind | string | unit | Android only. unit for JVM tests (no device), instrumented for on-device tests, e2e for end-to-end. |
scope | string | auto | Android only. Gradle task scope: module qualifies the task with the module path; root runs the root-level task (cascades across all modules). When kind: instrumented and scope is unset, defaults to root. Set scope: module explicitly for single-module behaviour. |
build_variant | string | debug | Android only. Overrides android.build_variant for this test step. |
task | string | — | Android only. Explicit Gradle task name (e.g. testDebugUnitTest). Overrides variant-based task selection. |
devices | object | — | Android only. Device config for instrumented runs. Fields: strategy (none/connected/named_emulators/managed), emulators (AVD names), group (managed device group), prompt_locally (interactive selection outside CI). |
Destination string format
platform=iOS Simulator,name=<SimulatorName>,OS=<Version>
platform=iOS,name=<DeviceName>
platform=macOS
Run xcodebuild -showdestinations -scheme <Scheme> (with -workspace or -project as appropriate)
to list all valid destination strings for your scheme on the current machine. Alternatively, run
shipit ai-session --goal local which calls destination discovery automatically and includes the
results in nextQuestion so an AI agent can ask which destinations to use.
Android examples:
workflows:
beta:
steps:
# JVM unit tests for a single module
- action: test
options:
kind: unit
build_variant: debug
# Instrumented tests — defaults to scope:root for multi-module projects
- action: test
options:
kind: instrumented
devices:
strategy: named_emulators
emulators: [Pixel_9_API_35]
# Explicit root-level aggregate task
- action: test
options:
task: testDebugUnitTest
scope: rootFor Android aggregate tasks, ShipItSwifty falls back to JUnit XML reports under build/test-results/<taskName>/ when Gradle stdout does not include a test summary.
test-results action options
Use test-results to parse an existing .xcresult bundle or Gradle JUnit XML directory into a normalized JSON report.
| Option | Type | Default | Description |
|---|---|---|---|
format | string | text | Output format hint: text, json, or markdown. |
platform | string | resolved platform | Explicit platform override when parsing outside a Shipfile-backed context. |
xcresult_path | string | auto-discover | Explicit path to a .xcresult bundle (iOS). Falls back to ./build/<scheme>-tests.xcresult or the first .xcresult under ./build/. |
report_path | string | auto-discover | Explicit path to a JUnit XML report directory (Android). Falls back to common Gradle build/test-results/... locations. |
failed_only | bool | false | Only include failed and errored tests in the parsed output. |
include_passed | bool | true | Include passed tests in the parsed output. |
report_output_path | string | — | Optional path to write the structured JSON report to disk. |
Archive action options
The archive action accepts inline step options for both iOS and Android:
| Option | Type | Default | Description |
|---|---|---|---|
scheme | string | app.scheme | Xcode scheme to archive (iOS). |
configuration | string | Release | Build configuration. |
export_method | string | app-store | Distribution method (iOS only): app-store, ad-hoc, development, enterprise. |
output_path | string | — | Output .xcarchive path (iOS) or .aab path (Android). |
include_symbols | bool | true | Include dSYMs (iOS only). |
module | string | android.module | Gradle module to bundle (Android). |
build_variant | string | release | Gradle bundle variant (Android). |
flavor | string | — | Product flavor name. Combined with build_variant for Gradle task names. Also used by Flutter and React Native archives. |
scope | string | module | Android Gradle task scope: module or root. |
gradle_properties | object | {} | Additional -P key=value properties passed to the Gradle bundle task (Android). |
infrastructure_retry | object | — | Retry the iOS archive for transient Apple provisioning-server failures that occur when -allowProvisioningUpdates contacts Apple's servers. Presence enables retries; omit to disable. Permanent failures (missing certificate, invalid team ID) are never retried. Recommended: { max_attempts: 3, initial_delay_seconds: 5, max_delay_seconds: 30 }. |
project_generation
Configuration for automatic project file generation (XcodeGen, Tuist) before Xcode-dependent steps.
| Key | Type | Default | Description |
|---|---|---|---|
tool | string | — | Generation tool: xcodegen or tuist |
command | string | — | Custom shell command (overrides tool) |
spec_path | string | — | Path to the project spec file (e.g. project.yml for XcodeGen) |
output_project | string | — | Expected output .xcodeproj path (used to verify generation succeeded) |
auto_generate | bool | true | Automatically run generation before Xcode-dependent actions. Set to false to skip. |
When project_generation.tool is configured, Workflow.run() automatically generates the Xcode project before the first Xcode-dependent step (build, test, archive, etc.), including steps reached through nested custom_actions. Generation is skipped when the output project already exists.
notifications.slack
| Key | Type | Description |
|---|---|---|
webhook_url | string | Incoming webhook URL (use ${SLACK_WEBHOOK_URL}) |
channel | string | Default Slack channel |
on_success | bool | Notify on success |
on_failure | bool | Notify on failure |
workflows
Workflows can be defined as a plain array of steps (legacy) or as an object with optional workflow-level overrides:
# Legacy format: plain array of steps
workflows:
beta:
- action: archive
- action: testflight
# New format: object with workflow-level overrides
workflows:
release:
build_variant: prodRelease
steps:
- action: archive
- action: play-store
options:
track: productionWorkflow-level overrides
| Key | Type | Description |
|---|---|---|
build_variant | string | Overrides android.build_variant for all steps in this workflow. Used by actions that auto-discover paths. |
flavor | string | Overrides android.gradle_properties.flavor for all steps in this workflow. |
steps | array | Required when using the object format. The ordered sequence of action steps. |
Each step:
| Key | Description |
|---|---|
action | Registered action name |
options | Optional key-value map passed to the action |
when | Optional condition. Reserved tokens are substituted, then the result must be truthy (true/1/yes) for the step to run; otherwise the step is skipped (status skipped) and the workflow continues. |
Use these AI-oriented commands to inspect the supported workflow surface:
swift run shipit ai-session --goal beta
swift run shipit schema --output json
swift run shipit inspect project --output json
swift run shipit generate --goal beta
swift run shipit validate yml --shipfile ./Shipfile.yml --output jsonai-session always emits JSON and is intended for AI/tooling integrations rather than direct human consumption.
Workflow notes:
exportcan write an IPA intoexport.output_directory.testflightanduploadcan reuse that exported IPA automatically when they run afterexportin the same workflow and no explicitipa/ipa_pathis set.validatereports an error whentestflightoruploadhas no explicit IPA and no prior export context.- Human output from
shipit run <workflow>now prints per-step summaries when available, including test pass/fail/skip counts, version strings, and archive artifact filenames.
custom_actions
User-defined composite actions — reusable, parameterized sequences of built-in actions (or other custom actions). Use these to avoid duplicating step blocks across workflows (for example sharing test → archive → export between beta and adhoc).
custom_actions:
<composite-name>:
description: "Human-readable summary (optional)."
parameters:
<param-name>:
type: string # string | bool | int | number | array | object | any
required: true # defaults to true when no default is set
default: <value> # optional fallback when call site omits the value
description: "..."
steps:
- action: <registered-action-or-other-composite>
options:
<option>: "{{param.<param-name>}}"Invocation is identical to a built-in action — a workflow step uses action: <composite-name> and forwards call-site values via its options: block:
custom_actions:
build_and_sign:
description: "Test, archive, and export the app with a chosen export method."
parameters:
method:
type: string
required: true
steps:
- action: test
- action: archive
- action: export
options:
method: "{{param.method}}"
workflows:
beta:
- action: build_and_sign
options:
method: app-store
- action: testflight
adhoc:
- action: build_and_sign
options:
method: ad-hoc
- action: notifyParameter reference syntax: {{param.NAME}}
Inside a step's options: block, string values may reference declared parameters using {{param.NAME}}. This delimiter is chosen to stay out of the way of every common template system that surrounds a Shipfile:
| System | Template syntax | Safe alongside {{param.X}}? |
|---|---|---|
Shipfile ${ENV_VAR} expansion | ${FOO} | ✅ Different delimiter. Env expansion runs before composite substitution, so you can freely mix: key: "{{param.track}}-${DEPLOY_ENV}". |
| GitHub Actions | ${{ env.X }}, ${{ secrets.X }} | ✅ Different delimiter (leading $ + double braces). |
| CircleCI parameters | << parameters.X >> | ✅ Different delimiter. |
| Xcode Cloud / shell | $VAR, ${VAR} | ✅ Different delimiter. |
Rules:
- Only string leaves in a step's
options:are scanned. Keys and non-string scalars are untouched. - When a string is exactly
{{param.NAME}}, the underlying typed JSON value is substituted (bool,int,array,object). When it appears inline with other text, the value is stringified. - Unknown parameter references cause
shipit validate ymlto report an error rather than silently expanding to an empty string.
Validation rules
shipit validate yml enforces:
- Custom action names must not collide with built-in action names.
steps:must contain at least one step.- Each step's
action:must resolve to a built-in or another declared custom action. - Each
{{param.NAME}}reference inside a step's options must match a declared parameter. - Required parameters must be supplied at the call site (or have a
default:). - The graph of composite-to-composite references must be acyclic.
AI-session integration
shipit ai-session includes the user's custom actions in the generated agent prompt (name, description, and declared parameters). Agents are instructed to prefer invoking an existing composite over duplicating its step sequence in a new workflow.
Workflow tokens & step conditions
Top-level workflow steps support reserved interpolation tokens and an optional when: condition. Together they let a single shipit run bump the version, distribute, then commit and tag the release — no shell or jq glue required.
Reserved tokens
| Token | Resolves to |
|---|---|
{{version}} | The marketing version (e.g. 1.2.3), from a prior version step or the current versioning source. |
{{build_number}} | The build number (e.g. 42). |
{{version_changed}} | true/false — whether the marketing version changed (false for a build-only bump, or when no version step ran). |
Rules:
- Tokens are substituted into string leaves of a step's
options:and into itswhen:value, at run time. - Values come from the most recent
versionstep's result. Before anyversionstep runs they are seeded best-effort from the current versioning source (and{{version_changed}}isfalse). - An unknown or not-yet-resolved token is left literal (and logged) rather than expanding to empty.
- These are distinct from composite
{{param.NAME}}references and from Shipfile${ENV_VAR}expansion. Resolution is scoped to top-level workflow steps; tokens insidecustom_actionssubsteps are not resolved in this release.
when: conditions
A step may carry when: "<expr>". Reserved tokens are substituted first, then the result is evaluated for truthiness: true, 1, or yes (case-insensitive) run the step; anything else — including an unresolved literal token — skips it (recorded with status skipped; the workflow continues). v1 supports a single truthy token, not operators or comparisons.
Skips are the only exception to fail-fast workflow semantics. A failing step still aborts the workflow as before.
Example: tag the released version in one shipit run
workflows:
release:
- action: version
options: { bump: patch } # or { bump: ${RELEASE_BUMP} } to drive from CI
- action: archive
- action: play-store
options: { track: production }
- action: git
options:
operation: commit
commit_message: "chore: release v{{version}} (build {{build_number}})"
- action: git
when: "{{version_changed}}" # skipped on build-only bumps
options:
operation: tag
tag_name: "v{{version}}"
- action: git
options:
operation: push
push_tags: trueshipit generate --goal release scaffolds this commit/tag/push tail for you — for both iOS and Android — and offers to drive the bump from CI via ${RELEASE_BUMP}. CI prerequisites the generator prints: a full-history checkout, write permission on the repo, and a configured git identity (user.name / user.email).
Environment Variables Summary
| Variable | Maps To |
|---|---|
ASC_KEY_ID | app_store_connect.key_id |
ASC_ISSUER_ID | app_store_connect.issuer_id |
ASC_PRIVATE_KEY | app_store_connect.private_key |
ASC_PRIVATE_KEY_PATH | app_store_connect.key_path |
VAULT_PASSWORD | Code signing passphrase |
SLACK_WEBHOOK_URL | notifications.slack.webhook_url |
SHIPIT_SCHEME | app.scheme |
SHIPIT_BUNDLE_ID | app.bundle_id |
SHIPIT_TEAM_ID | app.team_id |
android
Platform-specific Android configuration. These values are merged on top of shared config when --platform android is active or the platform is auto-detected as Android.
| Key | Type | Default | Env Var | Description |
|---|---|---|---|---|
build_system | string | native | SHIPIT_ANDROID__BUILD_SYSTEM | Build system: native, flutter, react_native, or kmp. See Build systems. |
module | string | app | — | Gradle module to build/bundle |
build_variant | string | release | — | Gradle build variant (e.g. release, debug) |
build_type | string | aab | — | aab (Android App Bundle) or apk |
scope | string | module | — | Default Gradle task scope: module qualifies tasks with the module; root runs from the Gradle root. |
test_kind | string | unit | — | Default test kind: unit (JVM tests), instrumented (on-device), e2e (end-to-end). |
package_name | string | — | SHIPIT_ANDROID__PACKAGE_NAME | Android application ID (e.g. com.example.app) |
keystore_path | string | — | — | Path to the release keystore |
keystore_password | string | — | ANDROID_KEYSTORE_PASSWORD | Keystore password |
keystore_alias | string | — | ANDROID_KEY_ALIAS | Key alias in the keystore |
key_password | string | — | ANDROID_KEY_PASSWORD | Key password |
rollout_fraction | float | — | — | Staged rollout fraction (0.0–1.0), for production track |
gradle_properties | map | {} | — | Extra -P key=value properties passed to Gradle |
gradlew_path | string | — | SHIPIT_ANDROID__GRADLEW_PATH | Explicit path to the gradlew script (auto-detected when omitted) |
gradle_project_dir | string | Shipfile directory | SHIPIT_ANDROID__GRADLE_PROJECT_DIR | Directory containing the Gradle root project |
gradle_flags | array | [] | — | Extra Gradle flags such as --stacktrace |
Google Play credentials
Set these environment variables for Google Play upload actions:
| Variable | Description |
|---|---|
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON | Full JSON content of the service account key file |
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_PATH | Path to the service account key JSON file |
Lookup notes:
package_nameis your AndroidapplicationId, usually fromapp/build.gradleorapp/build.gradle.ktsplay-storesteps require atrackoption (or--trackon the CLI) to target a Play Console track such asinternal,alpha,beta, orproduction- Create the service account in Google Cloud, enable the
Google Play Developer API, then invite that service account in Play ConsoleUsers and permissions - Give the service account Play Console permissions that match the rollout you want to perform
Env var naming: Android keystore variables support both the short form (
ANDROID_KEYSTORE_PASSWORD,ANDROID_KEY_PASSWORD,ANDROID_KEY_ALIAS) and the standardSHIPIT_form (SHIPIT_ANDROID__KEYSTORE_PASSWORD,SHIPIT_ANDROID__KEY_PASSWORD,SHIPIT_ANDROID__KEY_ALIAS). The short forms are checked as a compatibility fallback when theSHIPIT_names are not set.
ios
Platform-specific iOS overrides. Merged on top of shared config when --platform ios is active. All top-level app, code_signing, archive, export, testflight, and screenshots keys can appear here to override the shared defaults for iOS only.
| Key | Type | Default | Env Var | Description |
|---|---|---|---|---|
build_system | string | native | SHIPIT_IOS__BUILD_SYSTEM | native, flutter, react_native, or kmp. See Build systems. |
kmp_shared_module | string | shared | SHIPIT_IOS__KMP_SHARED_MODULE | Gradle module containing KMP framework/test tasks |
kmp_build_target | string | IosSimulatorArm64 | SHIPIT_IOS__KMP_BUILD_TARGET | KMP target linked before local xcodebuild build |
kmp_archive_target | string | IosArm64 | SHIPIT_IOS__KMP_ARCHIVE_TARGET | KMP target linked before xcodebuild archive |
kmp_test_task | string | iosSimulatorArm64Test | SHIPIT_IOS__KMP_TEST_TASK | KMP Gradle task used by shipit test --platform ios |
scheme | string | — | SHIPIT_IOS__SCHEME | iOS-specific Xcode scheme override |
workspace | string | — | SHIPIT_IOS__WORKSPACE | iOS-specific Xcode workspace override |
project | string | — | SHIPIT_IOS__PROJECT | iOS-specific Xcode project override |
ios:
build_system: native # native (default) | flutter | react_native | kmp
scheme: MyApp
archive:
export_method: app-storeBuild systems
build_system is orthogonal to platform: a single Kotlin Multiplatform or Flutter source tree can produce both an iOS .ipa and an Android .aab.
| Value | iOS compilation | Android compilation |
|---|---|---|
native | xcodebuild | gradlew assemble / bundle |
kmp | link KMP shared framework via Gradle → xcodebuild | gradlew :androidApp:assembleRelease / bundleRelease |
flutter | flutter build ipa (IPA at build/ios/ipa/) | flutter build apk / flutter build appbundle |
react_native | Metro bundle → xcodebuild archive + export | npx react-native build-android --tasks bundleRelease |
Auto-detection
When build_system is unset, ShipItSwifty resolves it automatically:
| Project marker | Detected value |
|---|---|
pubspec.yaml with a flutter: key | flutter |
package.json declaring react-native in dependencies | react_native |
build.gradle.kts applying kotlin("multiplatform") | kmp |
| None of the above | native |
KMP example
ios:
build_system: kmp
scheme: iosApp
workspace: iosApp/iosApp.xcworkspace
kmp_shared_module: shared
kmp_build_target: IosSimulatorArm64
kmp_archive_target: IosArm64
android:
build_system: kmp
module: androidApp
gradle_project_dir: .
versioning:
source: kmp
spec_path: gradle.propertiescoverage action options
The coverage action reads native coverage artifacts — it does not generate them.
| Option | Type | Default | Description |
|---|---|---|---|
platform | string | auto-detected | ios or android |
xcresult | string | auto-discovered | Explicit .xcresult bundle path (iOS) |
report | string | auto-discovered | Explicit JaCoCo XML report path (Android) |
first_party_only | bool | true | Suppress test bundles, SPM deps, and known vendor prefixes |
targets | bool | false | Show per-target (iOS) or per-module (Android) breakdown |
files | bool | false | Show per-file breakdown |
include_target | list | [] | Include only these targets (overrides first-party filter) |
exclude_target | list | [] | Exclude specific targets |
sort | string | coverage | coverage (lowest first — most actionable) or name |
limit | int | — | Cap number of entries shown |
format | string | text | text, json, or markdown |