How Telegram-iOS Configures Build Variants for Internal versus App Store Releases

Telegram-iOS distinguishes between internal beta and public App Store releases using compile-time macros defined in Xcode configuration files and injected by Bazel, which the BuildConfig module exposes as Boolean properties for runtime feature gating.

The TelegramMessenger/Telegram-iOS repository handles multiple distribution channels by statically defining build variants configured for internal versus App Store releases through a centralized compilation pipeline. By resolving environment flags at build time rather than runtime, the codebase prevents experimental features from leaking into production binaries while eliminating performance overhead from dynamic environment checks.

The BuildConfig Registry

The variant detection centers on the BuildConfig component located in submodules/BuildConfig/Sources/BuildConfig.m. This Objective-C implementation exposes two critical Boolean properties:

  • isInternalBuild – Returns true for beta or test flight builds, controlled by the APP_CONFIG_IS_INTERNAL_BUILD macro defined at lines 177–179.
  • isAppStoreBuild – Returns true only for binaries submitted to the App Store, controlled by the APP_CONFIG_IS_APPSTORE_BUILD macro defined at lines 181–183.

These values resolve to hardcoded constants at compile time, ensuring zero runtime overhead for environment detection.

Compile-Time Macro Injection

The build variants are determined before compilation through a pipeline involving Bazel rules and Xcode configuration files.

Bazel BUILD Configuration

In submodules/BuildConfig/BUILD, the Bazel rule passes variant flags to the compiler using -D preprocessor definitions (lines 26–30):

"-DAPP_CONFIG_IS_INTERNAL_BUILD={}".format(telegram_is_internal_build),
"-DAPP_CONFIG_IS_APPSTORE_BUILD={}".format(telegram_is_appstore_build),

These flags translate the build system variables into C macros that BuildConfig.m evaluates at compilation.

Xcode Configuration Files (.xcconfig)

Concrete values for each variant live in .xcconfig files within Telegram/Telegram-iOS/:

Internal (Fork) Variant – Config-Fork.xcconfig typically sets APP_CONFIG_IS_INTERNAL_BUILD=true for beta testing scenarios.

App Store Variant – Config-AppStoreLLC.xcconfig explicitly disables internal flags and enables store mode, including the real App Store ID:

APP_CONFIG_IS_INTERNAL_BUILD=NO
APP_CONFIG_IS_APPSTORE_BUILD=YES
APP_CONFIG_APPSTORE_ID=686449807

This configuration ensures the binary identifies correctly with Apple's commerce systems while excluding debug capabilities.

Runtime Feature Gating

Once instantiated, BuildConfig drives conditional logic throughout the Swift codebase, primarily within submodules/TelegramUI/Sources/AppDelegate.swift.

Initializing the Configuration

The AppDelegate creates the configuration object early in the lifecycle:

let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)

Conditional Feature Enabling

In AppDelegate.swift (lines 639–642), the code uses isAppStoreBuild to determine experimental feature availability:

let useBetaFeatures = !buildConfig.isAppStoreBuild
let sharedContext = SharedAccountContextImpl(
    // ...
    useBetaFeatures: useBetaFeatures,
    // ...
)

In-App Purchase Restrictions

The MakeTempAccountContext.swift file (lines 34–35) gates commerce functionality strictly to App Store builds:

if buildConfig.isAppStoreBuild {
    // Enable StoreKit transactions
}

Resource Selection

App icon selection (lines 951–952 in AppDelegate.swift) also respects the variant:

let appIcon = PresentationAppIcon(
    name: "BlueIcon",
    imageName: "BlueIcon",
    isDefault: buildConfig.isAppStoreBuild
)

Summary

  • Compile-time constants defined in .xcconfig files determine the build variant before code compilation.
  • Bazel BUILD rules inject these values as preprocessor macros (-DAPP_CONFIG_IS_INTERNAL_BUILD and -DAPP_CONFIG_IS_APPSTORE_BUILD) into submodules/BuildConfig/Sources/BuildConfig.m.
  • Zero runtime cost for environment checks because isInternalBuild and isAppStoreBuild evaluate to static Booleans.
  • Feature isolation ensures internal beta features never ship in Config-AppStoreLLC.xcconfig releases, while MakeTempAccountContext.swift and AppDelegate.swift consume these flags to toggle StoreKit, UI experiments, and app icons.

Frequently Asked Questions

How does Telegram-iOS detect if it's running an internal build?

The app checks the isInternalBuild property on the BuildConfig class, which returns the value of the APP_CONFIG_IS_INTERNAL_BUILD macro defined at compile time in submodules/BuildConfig/Sources/BuildConfig.m. This macro is set via Xcode configuration files like Config-Fork.xcconfig and injected by Bazel build rules.

What build system injects the variant macros in Telegram-iOS?

Bazel injects the macros through the BUILD file in submodules/BuildConfig/, specifically using compiler flags -DAPP_CONFIG_IS_INTERNAL_BUILD and -DAPP_CONFIG_IS_APPSTORE_BUILD that read values from Xcode .xcconfig files such as Config-AppStoreLLC.xcconfig.

Why use compile-time macros instead of runtime checks for build variants?

Compile-time macros eliminate the risk of debug code executing in production and remove runtime performance overhead for environment detection. As implemented in BuildConfig.m, these Booleans resolve to constants during compilation, allowing the compiler to optimize away unreachable code paths for each variant.

Which configuration file controls the official App Store release settings?

Telegram/Telegram-iOS/Config-AppStoreLLC.xcconfig defines the official App Store variant, setting APP_CONFIG_IS_APPSTORE_BUILD=YES and APP_CONFIG_IS_INTERNAL_BUILD=NO while specifying the production App Store ID (e.g., APP_CONFIG_APPSTORE_ID=686449807).

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 →