# Bundle ID / Package name properly formatted

- **Pattern:** `ab-001939` (`mobile-store-readiness.build-config.bundle-id-format`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001939
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001939)

## Why it matters

Bundle ID (iOS) and package name (Android) are the permanent, immutable identifiers that link every version of your app, every review, every user install, and every in-app purchase receipt to a single entity in the store databases. A malformed identifier — one that uses uppercase characters, hyphens, or has fewer than three segments — causes binary submission rejection before review begins. Using a generic placeholder like `com.example.app` in production is grounds for immediate rejection. Critically, once an app is published, changing the bundle ID or package name creates a brand-new app listing, breaking updates for all existing users. The Apple Bundle ID spec (apple-bundle-id) and Android Application ID spec (android-application-id) both mandate strict reverse domain notation.

## Severity rationale

Critical because an invalid or generic bundle ID/package name causes immediate binary rejection, and any post-publication change severs the update chain for all existing users permanently.

## Remediation

Set both identifiers in `app.json` before first submission. Use strict reverse domain notation: all lowercase, alphanumeric segments only, each segment starting with a letter, minimum three segments.

```json
// app.json
{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.yourcompany.appname"
    },
    "android": {
      "package": "com.yourcompany.appname"
    }
  }
}
```

Choose this identifier before first TestFlight or Play Console submission — it cannot be changed without losing all existing installs and reviews. Avoid hyphens in any segment (they are illegal in both specs). Segments must not start with a digit.

## Detection

- **ID:** `bundle-id-format`
- **Severity:** `critical`
- **What to look for:** Check `app.json` for `ios.bundleIdentifier` (iOS) and `android.package` (Android). Count the dot-separated segments in each identifier. Format should be reverse domain notation: `com.company.appname` (e.g., `com.example.myapp`). Package names should not contain numbers at the start of any segment, should be lowercase, and use only alphanumeric characters and dots.
- **Pass criteria:** Both bundleIdentifier (iOS) and package (Android) follow reverse domain notation: com.company.appname format, lowercase, valid characters only. Each identifier must have at least 3 dot-separated segments. Before evaluating, extract and quote the exact bundleIdentifier and package values found in `app.json` or build config.
- **Fail criteria:** Bundle ID or package name is missing, uses invalid characters (hyphens, underscores in the package name segment, uppercase letters), contains numbers at segment start (e.g., `com.2company.app`), has fewer than 3 segments, or uses a generic name like `com.example.app` in production.
- **Skip (N/A) when:** Project targets only iOS or only Android, so one of the identifiers is N/A.
- **Detail on fail:** Specify the issue. Example: `"Android package 'com.MyCompany.myapp' uses uppercase — must be lowercase: 'com.mycompany.myapp'"` or `"iOS bundleIdentifier missing from app.json"`
- **Remediation:** Bundle ID and package name uniquely identify your app in app stores. Follow the reverse domain notation format:
  1. In Expo app.json:
     ```json
     "ios": { "bundleIdentifier": "com.yourcompany.appname" },
     "android": { "package": "com.yourcompany.appname" }
     ```
  2. Rules:
     - Use reverse domain: com.yourcompany.appname
     - All lowercase
     - Alphanumeric and dots only (no hyphens or underscores)
     - Each segment must start with a letter, not a number
     - Must be unique — this ID locks your app to this identifier permanently
  3. Once released, never change the bundle ID/package name — it's permanent for app updates

## External references

- external apple-bundle-id — https://developer.apple.com/help/app-store-connect/create-an-app-record/register-a-bundle-id
- external android-application-id — https://developer.android.com/build/configure-app-module#set-application-id

Taxons: regulatory-conformance

HTML version: https://auditbuffet.com/patterns/ab-001939
