When developing iOS apps, managing sensitive configuration data like API keys and server URLs across different environments—such as development, staging, and production—can be a tricky task. These data must be kept secure, yet easily accessible during the build process.
This blog will show you how to streamline the management of sensitive data using .xcconfig files and environment variables, both in your local development setup and continuous integration (CI) pipelines, ensuring a more secure and efficient workflow.
Overview
The solution involves creating .xcconfig files for each environment, with placeholder values for sensitive data. These placeholder values are then replaced with real values from environment variables at build time.
For example, a ConfigDev.xcconfig file could look like this:
API_KEY = API_KEY_PLACEHOLDER
SDK_LICENSE_KEY = SDK_LICENSE_KEY_PLACEHOLDERDuring the build process, the API_KEY_PLACEHOLDER is replaced with the actual API key specific to the development environment.
Local Setup
Step 1
Create a shell script like setup_env.sh and place it in your project, for example, under the Scripts/EnvSetup directory. Here is the script gist: Link
Step 2
Run the setup_env.sh script to create the required .env and .local.xcconfig files.
sh setup_env.shThis will generate .env.dev, .env.stage, and .env.prod files, as well as corresponding .local.xcconfig files in the Configs directory.
Step 3
Open each .env file and populate them with the appropriate values for each corresponding environment variable.
Step 4
Before building your project in Xcode, run the update_xcconfig_from_env.sh script to substitute the placeholders in the .xcconfig files with values from the corresponding .env file.
Here is the update_xcconfig_from_env.sh gist: Link
sh update_xcconfig_from_env.sh devReplace dev with stage or prod as needed.
Step 5
Keep in mind that the .env and .local.xcconfig files should not be committed to version control, so make sure to add them to your .gitignore file. The project's build settings are set to use the .local.xcconfig files, so ensure you're always working in debug mode.
CI Setup
In your CI system, instead of using .env files, set up environment variables with the same names and values.
Before building the project, run the same update_xcconfig_from_ci_variables.sh script to replace the placeholders in the .xcconfig files with the values from the environment variables.
Script gist: Link
Benefits
This solution has several benefits:
- Sensitive data is not exposed in version control.
- It’s easy to manage configuration settings for different environments.
- It’s easy to update configuration settings without modifying the source code.
Bonus
For an easy and robust way to use.xcconfig variables, I created a property wrapper named @XCConfigValue. Check it out here
The usage should look like this:
enum Environment {
@XCConfigValue(key: "API_BASE_URL")
static var baseUrl: String
@XCConfigValue(key: "SUBSCRIBE_LIMIT")
static var subscribeLimit: Int
}
Conclusion
Managing sensitive data across multiple environments in iOS projects can be challenging, but using .xcconfig and .env files provides a secure and flexible solution. By keeping sensitive information out of version control and streamlining the configuration process for both local development and CI systems, you ensure your app stays secure while maintaining an efficient workflow.
At Povio, we're experts in building secure, high-performance iOS apps. If you're looking for help with your next project or need guidance on best practices for managing sensitive data, reach out to us—we’re here to help you take your app development to the next level.



