Managing API URLs in Xcode: Switching Environments with Build Configurations and Schemes
Learn how to set up Debug and Release build configurations in Xcode to serve different API base URLs without code changes.
06 Aug 2026, 14:56 UTC

Problem: Different API URLs for Development and Release
When you ship an iOS app, the same binary must sometimes point to a test server during development and a production server for App Store releases. Hard‑coding the URL forces you to maintain separate code branches or rebuild the app each time the endpoint changes.
Thesis: Use Xcode Build Configurations and Schemes
Xcode lets you define multiple build configurations (Debug, Release, Staging, etc.) and attach each to a scheme. By adding a user‑defined setting such as API_BASE_URL, the compiler can inject the correct value into Info.plist or make it available at runtime, giving you a single source tree that automatically selects the appropriate environment.
1. Configure Build Configurations and Schemes
A build configuration is a named set of compiler and linker flags plus any custom settings you add. Xcode ships with Debug and Release, but you can create additional ones such as Staging. Each configuration can hold its own value for a user‑defined setting, and Xcode replaces $(API_BASE_URL) with that value during the build. The scheme’s Build Configuration dropdown is the only place you need to change; the rest of your code stays untouched. You can also reference other build settings using $(OTHER_SETTING) if needed.
To switch environments without editing code, edit the scheme: open the scheme editor (click the scheme name → Edit Scheme), choose the Run action, go to the Info tab, and pick the desired Build Configuration from the dropdown. Checking Share Scheme stores the setting in version control, so teammates and CI pipelines use the same configuration.
2. Worked Example: API_BASE_URL
Suppose you need a staging URL for development and a production URL for release.
- Add the user‑defined setting: In the project navigator, select the target, open the Build Settings tab, scroll to User‑Defined, click the + button, and enter
API_BASE_URLas the key. - Set values per configuration: Click the + under the Debug column and type the staging URL (e.g.,
https://api.staging.example.com). Then click the + under the Release column and type the production URL (e.g.,https://api.example.com). - Reference the setting in Info.plist: Open the target’s Info.plist, add a new entry with key
API_URLand value$(API_BASE_URL). At runtime you can read it viaBundle.main.infoDictionary, or use the environment variable mechanism if you prefer. - Verify the build: Build the Debug configuration (⌘B). After the build, locate the generated .app bundle, unzip it, and inspect the Info.plist inside – it should show the staging URL.
- Switch to Release: In the scheme editor, change the Build Configuration to Release, then build again. The resulting Info.plist should now contain the production URL.
Risk note: The URL ends up inside the app bundle, so anyone who extracts the binary can see it. Do not store secret keys in a user‑defined setting; use secure key‑chain mechanisms instead.
3. Trade‑off and Limitation
The main limitation is visibility. Because the value is embedded in Info.plist, it becomes part of the binary and can be inspected with tools like otool or by unzipping the .app. Treat the setting as public data, not as a secret.
Another practical concern is scheme sharing. If you edit a scheme locally but never commit the change, teammates or CI pipelines will continue to use the old configuration. Always enable Share Scheme and commit the scheme file to version control.
4. Alternative Approaches and Verification
You could create separate targets, each with its own Info.plist, but that duplicates source files and complicates maintenance. Build configurations let you keep a single target while varying only runtime values, which reduces duplication and simplifies CI setup. This approach works for any environment‑specific value, not just API URLs.
To confirm the correct value is used at runtime, add a simple log statement such as print("API URL: \(API_BASE_URL)") in your app’s startup code. Run the app in Debug and Release builds; the console should display the expected URL.
If you need to keep the URL out of the binary, consider using a remote configuration service, but that adds complexity and may require a network call at launch.
Actionable Closing
Follow these steps to get started:
- Open your project, select the target, and add a user‑defined setting named
API_BASE_URL. - Populate the Debug and Release columns with the appropriate URLs.
- Edit the scheme: ensure the Run action points to the Debug configuration for development builds and Release for distribution.
- Build both configurations and inspect the resulting
Info.plistto confirm the correct URL is embedded. - Commit the scheme file and push the changes to your repository.
After committing, run a quick test on a device to ensure the correct URL is fetched. With this setup, you can switch environments without touching source code, keep your build process clean, and avoid maintaining multiple code bases.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.