A simple Swift terminal application that demonstrates loading environment variables from a .env
file using the swift-dotenv package.
- macOS 13.0 or later
- Swift 6.0 or later
- Clone this repository
- Make sure you have a
.env
file in the root directory of the project with your environment variables. Example:
# IMAP Server Credentials
IMAP_HOST=mail.example.com
IMAP_PORT=993
[email protected]
IMAP_PASSWORD=secret
To build and run the application:
# Build the package
swift build
# Run the application
swift run
If you're debugging the application in Xcode, you need to set a custom working directory to ensure the .env
file is found correctly:
- Open the project in Xcode by either:
- Opening the Package.swift file directly with Xcode
- Opening the project folder in Xcode (File > Open... and select the folder)
- Using "Open with Xcode" from Finder context menu on the project folder
- Xcode will automatically create a project and schemes for the Swift package
- Select the scheme for your executable target
- Choose "Edit Scheme..." from the scheme dropdown menu
- In the "Run" section, go to the "Options" tab
- Check "Use custom working directory" and set it to the directory containing your
.env
file (typically the project root directory) - Click "Close" to save the changes
While our application includes logic to find the project root by looking for Package.swift, setting the working directory explicitly in Xcode ensures the most reliable behavior during debugging.
The application:
- Determines the current working directory using a multi-step approach:
- First tries to find the project root by looking for the Package.swift file
- Then tries to get it from the ProcessInfo "PWD" environment variable
- Finally falls back to FileManager.default.currentDirectoryPath if all else fails
- Loads the environment variables from the
.env
file in the determined directory - Displays the loaded environment variables (with password masked for security)
The application includes a helper method to find the project root directory by looking for the Package.swift file:
func findProjectRootDirectory() -> String? {
// Start with the current directory
var currentPath = FileManager.default.currentDirectoryPath
// Check if Package.swift exists in the current directory
let packageSwiftPath = URL(fileURLWithPath: currentPath).appendingPathComponent("Package.swift").path
if FileManager.default.fileExists(atPath: packageSwiftPath) {
return currentPath
}
// If not found, try to navigate up the directory tree
// Get the executable path and work backwards
let executablePath = URL(fileURLWithPath: CommandLine.arguments[0]).deletingLastPathComponent().path
currentPath = executablePath
// Try up to 5 parent directories
for _ in 0..<5 {
let packageSwiftPath = URL(fileURLWithPath: currentPath).appendingPathComponent("Package.swift").path
if FileManager.default.fileExists(atPath: packageSwiftPath) {
return currentPath
}
// Move up one directory
currentPath = URL(fileURLWithPath: currentPath).deletingLastPathComponent().path
}
return nil
}
This is particularly useful when running the application from different contexts (e.g., Xcode, terminal, etc.) as it ensures the .env
file is always found correctly.
The swift-dotenv package (version 2.1.0 or higher) provides two ways to access environment variables:
-
Configure and access directly from Dotenv:
// Configure the environment with values from .env file in the current directory try Dotenv.configure() // Or specify a custom path try Dotenv.configure(atPath: "/path/to/.env") // Access values using subscript notation if let value = Dotenv["IMAP_HOST"] { // value is an Environment.Value object print("IMAP_HOST: \(value)") // or use stringValue to get the string representation print("IMAP_HOST: \(value.stringValue)") }
-
Using dynamic member lookup with camelCase:
// Configure the environment with values from .env file in the current directory try Dotenv.configure() // Note: Use camelCase for the property names if let value = Dotenv.imapHost { // value is an Environment.Value object // Use stringValue to get the string representation print("IMAP_HOST: \(value.stringValue)") }
- Make sure the
.env
file is in the root directory of your project (where Package.swift is located) - For security reasons, never commit your actual
.env
file with sensitive information to version control - The application will exit with an error if the
.env
file cannot be found or loaded