Xcode
xcconfig
URL configuration
iOS development
build settings

How do I configure full URLs in xcconfig files

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

xcconfig files are a clean way to keep environment-specific build settings out of the Xcode project UI. They work especially well for values such as API base URLs because you can define one value for Debug, another for Staging, and another for Release without scattering string literals through the app.

The usual pattern is to put the URL in the .xcconfig file, copy it into Info.plist through build setting substitution, and then read it at runtime from the app bundle. That keeps the value centralized and easy to override per configuration.

Define The URL In Your Configuration Files

Create a base configuration if you want shared defaults, then override the URL in environment-specific files.

xcconfig
// Base.xcconfig
API_BASE_URL = https://api.example.com
xcconfig
// Debug.xcconfig
#include "Base.xcconfig"
API_BASE_URL = https://api.dev.example.com
xcconfig
// Release.xcconfig
#include "Base.xcconfig"
API_BASE_URL = https://api.example.com

After creating those files, assign each one to the corresponding build configuration in Xcode. If the file is not attached to the build configuration, the setting exists on disk but never affects the target.

Expose The Value Through Info.plist

Build settings from .xcconfig are available at build time, not automatically at runtime. A common way to bridge that gap is to add a custom key in Info.plist whose value comes from the build setting.

xml
<key>APIBaseURL</key>
<string>$(API_BASE_URL)</string>

Now every build configuration can inject its own URL into the final app bundle without changing application code.

In Swift, read it like any other Info.plist value:

swift
1import Foundation
2
3enum AppConfig {
4    static var apiBaseURL: URL {
5        guard
6            let raw = Bundle.main.object(forInfoDictionaryKey: "APIBaseURL") as? String,
7            let url = URL(string: raw)
8        else {
9            fatalError("Missing or invalid APIBaseURL")
10        }
11        return url
12    }
13}
14
15print(AppConfig.apiBaseURL)

This keeps the runtime code strongly typed while leaving environment switching in build configuration.

Use Full URLs Carefully

A full URL often works better than splitting the value into host, scheme, and path unless you truly need those pieces independently. It is easier to read, easier to compare between environments, and less prone to accidental mismatches such as an HTTPS scheme pointing at a development host by mistake.

That said, decide whether you want only the base origin, such as https://api.example.com, or a full API root such as https://api.example.com/v1. Be consistent. If the app sometimes appends paths to a base URL and sometimes expects the version segment to already be present, bugs show up quickly.

You can also store related values alongside the URL, such as a feature-environment name or a websocket base URL, using the same pattern:

xcconfig
API_BASE_URL = https://api.staging.example.com
WEBSOCKET_URL = wss://ws.staging.example.com

Why xcconfig Is Better Than Hardcoding

Putting these URLs in .xcconfig keeps environment switching out of source files, which reduces merge conflicts and prevents accidental shipping of development endpoints. It also makes CI easier because different schemes and configurations can pick up different settings without editing Swift or Objective-C code before a build.

Another advantage is visibility. Someone reviewing the configuration files can see the runtime endpoint differences immediately, instead of hunting through conditional compilation blocks or multiple service-construction helpers.

Common Pitfalls

The most common mistake is forgetting that .xcconfig values are compile-time settings. Your app cannot read API_BASE_URL directly unless you pass it into something runtime-visible such as Info.plist or generated code. Another common issue is attaching the wrong .xcconfig file to the wrong build configuration, which makes Debug and Release silently point at the same backend. Teams also sometimes put secrets in .xcconfig files. That is fine for non-secret values such as public API origins, but client secrets should not be shipped in an app bundle. Finally, be consistent with trailing slashes. https://api.example.com and https://api.example.com/ behave differently when you build relative URLs.

Summary

  • Define environment-specific URLs in .xcconfig files and attach them to the correct build configurations.
  • Copy the build setting into Info.plist if the app needs the value at runtime.
  • Read the value from Bundle.main and convert it to URL in one place.
  • Keep the URL shape consistent across environments, especially around version paths and trailing slashes.
  • Use .xcconfig for public configuration values, not for secrets you would not want shipped to clients.

Course illustration
Course illustration

All Rights Reserved.