You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Generated from the config schema in src/core/config/ and config types in src/core/types/config.ts by npm run docs:gen — edit the source, then regenerate. For editor autocomplete and validation, run launch config schema --out launch.config.schema.json, then point your config at it: a JSON config adds a "$schema": "./launch.config.schema.json" key, while a .ts config (which can't carry $schema) is wired through VS Code's json.schemas setting or your editor's equivalent. Run launch config validate to check a config against this schema (it also reports cross-field semantic warnings, which never fail the command); pass a .json file to validate it verbatim, including unknown top-level keys.
Top-level fields
Field
Type
Required
Description
profiles
Record<string, BuildProfile>
Yes
Build profiles keyed by name.
credentials
string
No
Registered name of the credentials provider to use. Defaults to local (serves both platforms).
storage
string
No
Registered name of the artifact storage provider to use. Defaults to local.
buildEngine
string
No
Registered name of the build engine. Carries the iOS default fastlane (or eas for the cloud handoff); an Android build swaps that iOS baseline for its twin gradle unless overridden here.
submit
string | SubmitByPlatform
No
Where built artifacts are submitted, in one of two forms: a single registered submitter name (the iOS default app-store-connect, which an Android build swaps for its twin google-play; or eas) — the original, unchanged shape; or a per-platform SubmitByPlatform map, to fan one build out to several stores from this one config (e.g. an Android .aab to google-play and amazon-appstore). The pipeline resolves this to a store list per platform (see resolveSubmitters), so the build target and the store are no longer welded 1:1. See docs/adr/0006-platform-store-split.md.
appRoots
string[]
No
Glob roots to scan for apps. Defaults to the repo root.
products
Record<string, AppProducts>
No
Declarative App Store Connect product catalog, keyed by iOS bundle id. Drives launch sync, which reconciles each app's subscriptions, in-app purchases, and pricing on App Store Connect to match this. Absent for apps that sell nothing. See AppProducts.
notify
object
No
Build/submit completion notifications (webhook + shell hook). Absent = no notifications. See NotifyConfig.
release
object
No
iOS public-release policy for launch release (release type, scheduled date, phased rollout, export compliance, release notes). Absent = the safe defaults (go live after approval, all at once). See ReleaseConfig.
gameCenter
Record<string, GameCenterConfig>
No
Game Center achievements & leaderboards, keyed by iOS bundle id. Drives launch game-center. The single-config form of gamecenter.config.json (still accepted for back-compat). See GameCenterConfig.
appClips
Record<string, AppClipsConfig>
No
App Clip card metadata, keyed by the parent app's iOS bundle id. Drives launch app-clips. The single-config form of appclips.config.json (still accepted for back-compat). See AppClipsConfig.
releaseAttributes
Record<string, ReleaseAttributesConfig>
No
App Store release attributes (age rating, categories, price, review details), keyed by iOS bundle id. Drives launch release-config. The single-config form of release.config.json (still accepted for back-compat). Distinct from release (the release policy). See ReleaseAttributesConfig.
wallet
object
No
Team-level Apple Pay merchant ids & Wallet pass type ids. Drives launch wallet. The single-config form of wallet.config.json (still accepted for back-compat). See WalletConfig.
euDistribution
object
No
Team-level EU alternative-distribution domains (DMA). Drives launch eu-distribution. The single-config form of eu-distribution.config.json (still accepted for back-compat). See EuDistributionConfig.
configFiles
object
No
Optional non-default paths for the sidecar-only surfaces' *.config.json files (availability, accessibility, experiments, custom pages). Lets launch plan / launch drift find a sidecar that isn't at its default filename, since those surfaces have no typed field here. Omit to use defaults. See SurfaceConfigFiles.
aws
object
No
AWS EC2 Mac settings for remote (off-Mac) builds. Only needed when building via --remote aws.
storageConfig
object
No
Bucket/endpoint settings for a cloud StorageProvider (s3 / supabase). Required when storage names a cloud provider — it's where ad-hoc install links and OTA update manifests are hosted. Secrets stay out: access keys resolve from env / the OS secret store, never from here.
artifactDir
string
No
Where the local storage provider writes build binaries and raw objects (install plists, OTA manifests). A relative path resolves against the project root (the launch.config.ts directory); a leading ~/ expands to the home directory; an absolute path is used as-is. Omit to use the global ~/.launch/artifacts (the default — existing projects are unaffected). launch init and the no-args wizard scaffold this as the in-repo ./.launch/artifacts and add it to .gitignore, so build binaries never get committed. Only the local provider observes it — cloud stores key off StorageConfig. The history index stays under ~/.launch, so build history and retention span projects regardless of where the binaries land.
artifactRetentionDays
number
No
How many days a local build binary is kept before the artifact store auto-prunes it to reclaim disk (the newest build per app+platform is always kept, so a promotable artifact never disappears). Runs after each successful local build. Defaults to 30 when omitted; set to 0 to disable the automatic sweep entirely (launch builds prune still works on demand). Only the local provider observes this — cloud stores manage retention through their own bucket lifecycle rules.
envExclude
string[]
No
Env var names that must NEVER be injected into a build — a hard denylist applied across every layer (.env, .env.<profile>, keychain, profile env:, even an explicit --env). A matched name is dropped outright, so it can't reach the build subprocess and therefore can't be baked into the shipped app even by an app.config.js that forwards process.env. Each entry is either an exact, case-sensitive name or a PREFIX* wildcard: OPENAI_* drops every name starting with OPENAI_ (e.g. OPENAI_API_KEY, OPENAI_ORG_ID), so a whole family of backend keys collapses to one line instead of being listed individually. Wildcards anchor at the START — there is no tail/*_KEY form, by design, since that would also snag a publishable EXPO_PUBLIC_..._KEY. This is the home for backend-only values that sit in the app's .env for local tooling but must never ship (e.g. OPENAI_API_KEY, a server-side SENTRY_AUTH_TOKEN). It is distinct from launch secret set: a stored secret is still injected — the build needs it — it's just moved out of plaintext; envExclude means "don't inject this at all". A name matched here is exempt from the .env.example missing-key gate (even when no layer sets it). Omit (or []) to exclude nothing.
mcp
object
No
How launch mcp exposes Launch to AI agents — chiefly which capability tiers it may offer. Absent = least privilege (read-only tools). See McpConfig.
Types
AchievementConfig
One declared Game Center achievement: Apple's create attributes plus its default-locale localization.
Field
Type
Required
Description
vendorIdentifier
string
Yes
Developer-chosen stable id used to match config to Apple's record (never shown to players).
referenceName
string
Yes
Internal name shown in App Store Connect.
points
number
Yes
Points awarded (Apple caps the total across achievements at 1000).
showBeforeEarned
boolean
No
Whether the achievement is visible to players before it's earned (default false).
repeatable
boolean
No
Whether it can be earned more than once (default false).
name
string
Yes
Player-facing title in the localization.
beforeEarnedDescription
string
Yes
Player-facing description shown before the achievement is earned.
afterEarnedDescription
string
Yes
Player-facing description shown after it's earned.
locale
string
No
Locale for the localization above (default en-US).
AppClipConfig
One App Clip's declared card metadata. Both fields are optional and reconciled independently, so a clip may declare just an action, just localizations, or both.
Field
Type
Required
Description
action
"OPEN" | "VIEW" | "PLAY"
No
The card's call-to-action button (OPEN / VIEW / PLAY).
localizations
Record<string, AppClipLocalizationConfig>
No
Per-locale card subtitles, keyed by Apple locale (e.g. en-US).
AppClipLocalizationConfig
One locale of an App Clip card: the subtitle shown under the app name in that locale.
Field
Type
Required
Description
subtitle
string
Yes
AppClipsConfig
An app's declared App Clips — the appclips.config.json document, or one entry of appClips (keyed by the parent app's iOS bundle id). Each App Clip is keyed by its own bundle id (e.g. com.acme.app.Clip), which is how a config entry is matched to the clip the build produced. Reconciled by launch app-clips.
Field
Type
Required
Description
clips
Record<string, AppClipConfig>
Yes
AppProducts
The declarative App Store Connect product catalog for ONE app, keyed by iOS bundle id under products. launch sync reconciles the live account to match this: it creates missing groups/subscriptions/IAPs, fills in localizations, and sets prices. launch offers reconciles the subscription offers nested under SubscriptionGroupConfig and the promotedPurchases ordering. All fields are optional so an app can sell only subscriptions, only one-off purchases, or (with none set) nothing.
Field
Type
Required
Description
subscriptionGroups
SubscriptionGroupConfig[]
No
Auto-renewable subscription groups and the subscriptions within them.
inAppPurchases
InAppPurchaseConfig[]
No
One-off in-app purchases.
promotedPurchases
PromotedPurchaseConfig[]
No
Promoted purchases in product-page display order (launch offers reorders the live list to match).
BuildProfile
A named build profile from launch.config.ts (e.g. production, preview). Holds only Launch-specific settings; app facts stay in app.json. A profile maps to a .env file whose values are injected into the build and gates the artifact on size.
Field
Type
Required
Description
name
string
Yes
Profile name as referenced by --profile.
envFile
string
No
Dotenv file to load for this profile, relative to the app dir. Defaults to .env.
env
Record<string, string>
No
Inline env vars for this profile, merged into the build/update/release environment. They sit above the dotenv files (.env.local, .env.<profile>, .env) but below keychain secrets and --env flags in the precedence ladder — see core/env.tsresolveEnv. Use for non-secret, committed config that should travel with the profile; keep real secrets in launch secret.
ssl
boolean
No
Enable SSL pinning for this profile (mirrors the existing build.ts toggle). Defaults to false.
sizeBudgetMB
number
No
Per-device download-size budget in megabytes. When the size report exceeds it, the build soft-gates (asks for confirmation) rather than failing. Defaults to 200 (Apple's cellular line).
track
"internal" | "closed" | "open" | "production"
No
Android-only: default Play track for launch build android when --track is omitted. Defaults to internal (the only safe target for a fresh account). Ignored on iOS.
rollout
number
No
Android-only: default staged-rollout fraction (0–1) for production releases when --rollout is omitted. Defaults to 1.0 (full rollout). Ignored on iOS.
EuDistributionDomainConfig
One authorized EU distribution domain: the host plus a human-readable reference name.
Field
Type
Required
Description
domain
string
Yes
The domain authorized to host distribution packages (e.g. downloads.acme.com).
referenceName
string
Yes
A label shown in App Store Connect to identify the domain.
GameCenterConfig
An app's declared Game Center achievements and leaderboards — the gamecenter.config.json document, or one entry of gameCenter (keyed by iOS bundle id). Either list may be omitted. Reconciled additively by launch game-center.
Field
Type
Required
Description
achievements
AchievementConfig[]
No
leaderboards
LeaderboardConfig[]
No
GroupLocalization
One locale's display name for a subscription GROUP. Groups carry only a name (no description); it's shown at the point of purchase grouping the subscription levels. Without one, every subscription in the group is stuck in "Missing Metadata", so at least one is required per group.
Field
Type
Required
Description
locale
string
Yes
App Store locale code, e.g. en-US.
name
string
Yes
Customer-facing group name.
InAppPurchaseConfig
One non-subscription in-app purchase (consumable, non-consumable, or non-renewing subscription). productId is the globally-unique Apple product id and the reconciler's natural key. Add a PlayProductOverride under play to also publish it to Google Play.
Field
Type
Required
Description
productId
string
Yes
Apple product id, e.g. com.acme.coins.100. Globally unique; the reconciler matches on it.
referenceName
string
Yes
Internal reference name shown only in App Store Connect.
Per-locale display copy; at least one entry is required for a submittable product.
price
object
No
Baseline price. Omit only to price manually in the UI.
play
object
No
Google Play overrides; present this to also publish the product to Play (see PlayProductOverride).
IntroductoryOfferConfig
An introductory offer (Apple's subscriptionIntroductoryOffers) — the one auto-applied first-time discount. Apple allows at most one per (subscription, territory); when territory is omitted it applies to all territories the subscription is sold in. territory is the reconciler's natural key.
How scores are formatted (e.g. INTEGER, ELAPSED_TIME_SECOND).
submissionType
"BEST_SCORE" | "MOST_RECENT_SCORE"
Yes
Whether the board keeps each player's best or most recent score.
scoreSortType
"ASC" | "DESC"
Yes
Whether higher (DESC) or lower (ASC) scores rank first.
name
string
Yes
Player-facing title in the localization.
locale
string
No
Locale for the localization above (default en-US).
OfferCodeConfig
A subscription offer-code campaign (Apple's subscriptionOfferCodes) — a redeemable promo that grants an introductory price. name is the reconciler's natural key (unique per subscription); offer-code terms are immutable once created, so the reconciler only ever creates a missing code, never edits one (deactivation is the explicit launch offers deactivate action). One-time-use and custom code batches are generated separately (the imperative launch offers codes subcommands), not declared here.
Whether the code stacks with or replaces the intro offer.
OfferPrice
One territory's discounted price for an offer, resolved to an Apple subscription price point exactly like ProductPrice (the customer-facing amount must equal a point on Apple's fixed ladder). Omit prices entirely for a FREE_TRIAL offer.
Field
Type
Required
Description
territory
string
No
Territory whose price point is matched, e.g. USA. Defaults to USA.
customerPrice
number
Yes
Exact customer-facing price in the territory's currency, e.g. 4.99. Must equal an Apple price point.
PlayPriceConfig
A Google Play price: an exact amount in a currency's micro-units (millionths) plus the ISO currency code. Play has no price-point ladder — "1990000" with currency "USD" is $1.99. Used for both a product's default price and any per-region overrides. Kept distinct from ProductPrice because the two stores model money differently (Apple resolves a fixed price point; Play takes a literal micro-unit amount), so a single shared price field can't serve both.
Field
Type
Required
Description
priceMicros
string
Yes
Amount in micro-units: 1,000,000 = one whole unit of currency.
currency
string
Yes
ISO 4217 currency code, e.g. USD.
PlaySubscriptionOfferConfig
One Google Play offer on a subscription's base plan — a free trial, an introductory price, or both (Play allows up to two offer phases). offerId is the natural key the reconciler matches on. Set freeTrialDuration for a free phase and/or introPrices for a discounted phase; an offer with neither is rejected (it would discount nothing).
Field
Type
Required
Description
offerId
string
Yes
Play offer id (unique within the base plan).
freeTrialDuration
string
No
Free-trial length as an ISO-8601 duration (e.g. P1W, P1M). Omit for no trial phase.
introPrices
Record<string, PlayPriceConfig>
No
Introductory per-region prices (region code → micro-units + currency). Omit for no intro phase.
introRecurrenceCount
number
No
How many billing periods the introductory price repeats for. Defaults to 1.
ProductLocalization
One locale's customer-facing copy for a subscription or in-app purchase — the display name (and optional description) shown on the product page. Apple keeps a product in "Missing Metadata" until it has at least one localization, so the reconciler rejects an empty list rather than silently creating an unsubmittable product. The locale is the natural key the reconciler matches on.
Field
Type
Required
Description
locale
string
Yes
App Store locale code, e.g. en-US.
name
string
Yes
Customer-facing display name (Apple limit: 30 characters).
description
string
No
Customer-facing description (Apple limit: 45 characters). Omitted when not provided.
PromotedPurchaseConfig
One promoted purchase (Apple's promotedPurchases) — an IAP or subscription surfaced on the app's App Store product page. Declaration order in promotedPurchases is the display order Apple shows; launch offers reorders the live list to match. productId references an existing subscription or in-app purchase; the reconciler resolves it to the live resource.
Field
Type
Required
Description
productId
string
Yes
Apple product id of the subscription or in-app purchase to promote.
visibleForAllUsers
boolean
No
Whether the promotion is visible to all users (vs. targeted via the API). Defaults to true.
enabled
boolean
No
Whether the promotion is enabled. Defaults to true.
PromotionalOfferConfig
A promotional offer (Apple's subscriptionPromotionalOffers) — a developer-presented discount surfaced in-app to existing/lapsed subscribers. offerCode is the product-level identifier the app passes to StoreKit at redemption; it is the reconciler's natural key (unique per subscription).
How the offer discounts. FREE_TRIAL must omit prices.
numberOfPeriods
number
Yes
How many duration units the offer spans.
prices
OfferPrice[]
No
Per-territory discounted prices. Required unless offerMode is FREE_TRIAL.
name
string
Yes
Internal name shown in App Store Connect.
offerCode
string
Yes
Product-level offer identifier the app references in StoreKit — the reconciler's key.
ReleaseAttributesConfig
An app's declared App Store release attributes — age rating, App Store categories, base price, and App Review details — the release.config.json document, or one entry of releaseAttributes (keyed by iOS bundle id). Every section is optional and reconciled independently by launch release-config, so a file may declare only the attribute(s) you manage as code (e.g. just pricing). Named to avoid colliding with ReleaseConfig, which is the distinct iOS release policy (when/how a version goes live).
Field
Type
Required
Description
ageRating
Record<string, string | boolean>
No
Age-rating answers as Apple's name → value map (enum strings or booleans); only changed keys are sent.
categories
ReleaseCategories
No
pricing
ReleasePricing
No
reviewDetails
ReviewDetailsConfig
No
ReleaseCategories
Declared primary/secondary App Store categories (appCategories ids such as PRODUCTIVITY).
Field
Type
Required
Description
primary
string
No
secondary
string
No
ReleasePricing
Declared base price: a customer price (e.g. 9.99) in a base territory Apple equalizes from.
Field
Type
Required
Description
baseTerritory
string
No
Base territory to anchor the price on (default USA).
customerPrice
number
Yes
The customer-facing price in the base territory; must match one of Apple's price-ladder rungs.
ReviewDetailsConfig
Declared App Review details: the contact Apple reaches and the demo account its reviewer signs in with. Field names match Apple's appStoreReviewDetails attributes verbatim. demoAccountPassword is never read back from Apple or logged.
Field
Type
Required
Description
contactFirstName
string
No
contactLastName
string
No
contactPhone
string
No
contactEmail
string
No
demoAccountRequired
boolean
No
demoAccountName
string
No
demoAccountPassword
string
No
The reviewer demo-account password. Prefer an indirection over a plaintext literal so the secret needn't sit in a repo-committed config (per "secrets never touch the repo"): env:VAR_NAME reads it from the environment, keychain:ACCOUNT from the OS keychain — both resolved only at submit time, so a plan never reads or holds it. Any other value is used as a literal (backward compatible).
notes
string
No
SubmitByPlatform
Field
Type
Required
Description
ios
string[]
No
android
string[]
No
tvos
string[]
No
macos
string[]
No
visionos
string[]
No
SubscriptionConfig
One auto-renewable subscription product inside a SubscriptionGroupConfig. productId is the globally-unique Apple product id the app references at runtime and the reconciler's natural key. Add a PlaySubscriptionOverride under play to also publish it to Google Play.
Field
Type
Required
Description
productId
string
Yes
Apple product id, e.g. com.acme.pro.monthly. Globally unique; the reconciler matches on it.
referenceName
string
Yes
Internal reference name shown only in App Store Connect (Apple limit: 64 characters).
Per-locale display copy; at least one entry is required for a submittable product.
price
object
No
Baseline price. Omit only to price manually in the UI.
offerCodes
OfferCodeConfig[]
No
Offer-code campaigns to ensure exist on this subscription (launch offers).
promotionalOffers
PromotionalOfferConfig[]
No
Promotional offers to ensure exist on this subscription.
introductoryOffers
IntroductoryOfferConfig[]
No
Introductory offers (at most one per territory) to ensure exist on this subscription.
winBackOffers
WinBackOfferConfig[]
No
Win-back offers to ensure exist on this subscription.
reviewScreenshot
string
No
Path (relative to the app directory) to this subscription's App Review screenshot — the image Apple requires before a subscription can be submitted. launch sync uploads it via the reservation flow, idempotently: it's skipped when the live screenshot's MD5 already matches the local file. Omit to attach it by hand in App Store Connect. Reconciled in core/ascScreenshots.ts, not here.
play
object
No
Google Play overrides; present this to also publish the subscription to Play (see PlaySubscriptionOverride).
SubscriptionGroupConfig
A subscription group — Apple's container for mutually-exclusive subscription levels (a customer holds at most one active subscription per group). referenceName is unique within the app and is the reconciler's natural key for the group.
Field
Type
Required
Description
referenceName
string
Yes
Internal reference name (unique within the app) — the reconciler's natural key for the group.
localizations
GroupLocalization[]
Yes
Per-locale group display name; at least one entry is required (else the group's subs stay unsubmittable).
subscriptions
SubscriptionConfig[]
Yes
The subscription levels in this group.
WalletIdConfig
One declared Apple identifier: the reverse-DNS id plus a human-readable name shown in the portal.
Field
Type
Required
Description
identifier
string
Yes
The identifier to register (e.g. merchant.com.acme.app or pass.com.acme.coupon).
name
string
Yes
A label shown in App Store Connect / the developer portal.
WinBackOfferConfig
A win-back offer (Apple's winBackOffers) — a discount shown on the App Store to lapsed subscribers, gated on how long they previously paid and how long ago they churned. offerId is the reconciler's natural key (unique within the app). Win-back offers carry no images here — promotion artwork is the promotionIntent auto-generated path; custom artwork is a deferred follow-up.