🔧

Apple公式Swift Configurationを試してみた

に公開

目次

  1. はじめに
  2. Swift Configurationとは
  3. 基本的な使い方
  4. 応用的な機能
  5. swift-envで目指したAPI設計
  6. まとめ

1. はじめに

本記事では、2025年12月に1.0が正式リリースされたApple公式の設定管理ライブラリ「Swift Configuration」を紹介します。基本的な使い方から応用機能までを解説し、最後に自分のユースケース向けに作ったラッパーライブラリについても触れます。

なお、本記事はサーバーサイドSwiftでiOSアプリ開発をどこまで効率化できるかを検証するシリーズの第1回です。私は2025年12月頃から、Vaporを使ったバックエンド構築とiOSアプリとのコード共有を試しており、その過程で開発したSwiftパッケージについて本シリーズで解説していきます。


2. Swift Configurationとは

Swift Configurationは、Appleが開発した設定管理ライブラリです。2025年10月にベータ版が公開され、12月11日に1.0が正式リリースされました。

解決する課題

Swift開発では、設定値を環境変数、JSONファイル、コマンドライン引数など複数のソースから読み込む必要があります。従来はこれらを手動で組み合わせる必要がありました。

// 従来のアプローチ(手動で組み立てる)
let projectId = ProcessInfo.processInfo.environment["GCP_PROJECT_ID"] ?? "default-project"
let port = Int(ProcessInfo.processInfo.environment["SERVER_PORT"] ?? "") ?? 8080

Swift Configurationは、この課題を統一的なAPIで解決します。

設計思想:リーダーとプロバイダーの分離

Swift Configurationの核心は、設定を読み取るAPI(リーダー)と設定の供給元(プロバイダー)を分離するという設計思想です。

アプリやライブラリはConfigReaderを通じて設定を読み取り、実際のプロバイダー(環境変数、JSONファイルなど)はエントリーポイントで一度だけ設定します。これにより、ライブラリは特定の設定ソースに依存せずに設定を受け取れます。


3. 基本的な使い方

ConfigReaderとプロバイダー

最もシンプルな使い方は、EnvironmentVariablesProviderを使って環境変数から設定を読み込むパターンです。

import Configuration

let config = ConfigReader(provider: EnvironmentVariablesProvider())
let httpTimeout = config.int(forKey: "http.timeout", default: 60)
print("タイムアウト: \(httpTimeout)秒")

プロバイダー階層による優先度解決

複数のプロバイダーを組み合わせることで、優先度順に値を解決できます。

let config = ConfigReader(providers: [
    EnvironmentVariablesProvider(),
    try await FileProvider<JSONSnapshot>(filePath: "/etc/config.json")
])

// 1. 環境変数に値があればそれを使用
// 2. なければJSONファイルの値を使用
// 3. どちらにもなければデフォルト値を使用
let timeout = config.int(forKey: "http.timeout", default: 60)

例えば、環境変数HTTP_TIMEOUT=15が設定されていれば15、なければJSONファイルの"http": { "timeout": 30 }から30、どちらもなければデフォルトの60が返ります。

キー変換規則

EnvironmentVariablesProviderは、ドット区切りのキーを自動的に大文字のアンダースコア区切りに変換します。

キー 環境変数名
http.timeout HTTP_TIMEOUT
gcp.project.id GCP_PROJECT_ID
firebase.emulator FIREBASE_EMULATOR

スコープ付きリーダー

scoped(to:)メソッドを使うと、特定のプレフィックスを持つキーだけを扱うリーダーを作成できます。

let config = ConfigReader(provider: EnvironmentVariablesProvider())

// "emulator" スコープ付きリーダーを作成
let emulatorConfig = config.scoped(to: "emulator")

// "emulator.firestore.host" → 環境変数 EMULATOR_FIRESTORE_HOST を参照
let firestoreHost = emulatorConfig.string(forKey: "firestore.host", default: "localhost")

これにより、関連する設定をグループ化して管理できます。


4. 応用的な機能

Swift Configurationは基本的な設定読み込みだけでなく、本番環境で必要な機能を幅広くサポートしています。

3つのアクセスパターン

設定値へのアクセス方法として、3つのパターンが用意されています。

パターン 用途 特徴
同期(get) 起動時の設定読み込み 即座に値を返す
非同期(fetch) リモート設定の取得 async/awaitで待機
監視(watch) 設定変更のリアルタイム検知 AsyncSequenceで値の変更を受け取る

サーバーアプリケーションでは、起動時に同期パターンで設定を読み込み、実行中はwatchパターンで設定変更を監視するといった使い分けができます。

ホットリロード

ReloadingFileProviderを使うと、設定ファイルの変更を自動的に検知し、サービスを再起動せずに設定を更新できます。

// Package.swiftでReloadingトレイトを有効化
// traits: [.defaults, "Reloading"]

let config = ConfigReader(providers: [
    EnvironmentVariablesProvider(),
    try await ReloadingFileProvider<JSONSnapshot>(filePath: "/etc/config.json")
])

watchパターンと組み合わせることで、設定ファイルの変更をリアルタイムに反映できます。

型変換

基本型(String、Int、Double、Bool)に加えて、以下の型への変換をサポートしています。

  • URL、UUID: 文字列からの自動変換
  • Date: ISO8601形式からの変換
  • FilePath: ファイルパス型への変換
  • 列挙型: RawRepresentable<String>に準拠した列挙型
  • カスタム型: ExpressibleByConfigStringプロトコルに準拠した任意の型

シークレット保護

機密性の高い設定値(APIキー、パスワードなど)を安全に扱うための機能があります。isSecretフラグを設定することで、アクセスログへの出力時に自動的にマスキングされ、意図しない露出を防ぎます。

アクセスログ

AccessLoggerを使うと、どの設定値がいつ読み込まれたかをSwiftLogに出力できます。デバッグや監査に役立ちます。

// Package.swiftでLoggingトレイトを有効化
// traits: [.defaults, "Logging"]

アクセスイベントには、要求されたキー、呼び出し元、取得された値、使用されたプロバイダーなどの情報が含まれます。

利用可能なプロバイダー

Swift Configurationには、以下のプロバイダーが組み込まれています。

プロバイダー 用途
EnvironmentVariablesProvider 環境変数
CommandLineArgumentsProvider コマンドライン引数(opt-in)
FileProvider<JSONSnapshot> JSONファイル
FileProvider<YAMLSnapshot> YAMLファイル(opt-in)
ReloadingFileProvider ホットリロード対応ファイル(opt-in)
DirectoryFilesProvider ディレクトリ内の複数ファイル
InMemoryProvider テスト用のインメモリストレージ
KeyMappingProvider キー名の変換

また、ConfigProviderプロトコルに準拠することで、カスタムプロバイダーを実装することもできます。


5. swift-envで目指したAPI設計

自分のプロジェクトでSwift Configurationを使う中で、Swiftマクロを使って宣言的に書けるラッパーswift-envを作りました。

自分が欲しかったAPI

私が欲しかったのは、プロパティにキーとデフォルト値を宣言するだけで設定構造体を定義できるAPIでした。

@Env
struct GCPConfig {
    @Value("gcp.project.id", default: "my-project")
    var projectId: String

    @Value("firebase.emulator", default: false)
    var useEmulator: Bool
}

@Envと@Valueマクロを使うことで、Keys enum、Defaults enum、initメソッドを自動生成します。使う側は宣言した通りの設定構造体が生成され、ConfigReaderを渡すだけで初期化できます。

let config = ConfigReader(provider: EnvironmentVariablesProvider())
let gcp = GCPConfig(config: config)
print(gcp.projectId)  // 環境変数 GCP_PROJECT_ID または "my-project"

スコープ対応

@Env(scope:)でスコープを指定すると、内部でscoped(to:)が自動的に呼び出されます。

@Env(scope: "emulator")
struct EmulatorConfig {
    @Value("firestore.host", default: "localhost")
    var firestoreHost: String

    @Value("firestore.port", default: 8090)
    var firestorePort: Int
}

// 使用時はルートのconfigを渡すだけ
let emulator = EmulatorConfig(config: config)
// 環境変数 EMULATOR_FIRESTORE_HOST, EMULATOR_FIRESTORE_PORT を参照

設定構造体のグループ化

複数の設定構造体をまとめたい場合は、@EnvGroupマクロを使います。

@EnvGroup
struct AppConfig {
    let gcp: GCPConfig
    let emulator: EmulatorConfig
    let server: ServerConfig
}

// 一括読み込み
let appConfig = AppConfig.load()
print(appConfig.gcp.projectId)
print(appConfig.emulator.firestoreHost)

ここで重要なのは、AppConfig自体はユーザーが定義する通常の構造体ですが、@EnvGroupマクロを付けることでload()メソッドが自動生成される点です。このメソッドは内部でConfigReaderを作成し、すべての子設定構造体を一括で初期化します。

位置付け

swift-envは、Swift Configurationの機能をそのまま活用しつつ、自分のユースケースに合わせて宣言的なAPIを提供するラッパーです。環境変数からの読み込みに特化しており、Swift Configurationが持つJSON/YAMLプロバイダーやホットリロードなどの豊富な機能をすべてサポートしているわけではありません。

公式ライブラリが提供するAPIをそのまま使うか、自分好みにラップするかは、プロジェクトの要件次第です。


6. まとめ

Swift Configuration 1.0の正式リリースにより、Swiftエコシステムに統一的な設定管理APIが提供されました。

  • 環境変数、JSON、YAMLなど複数ソースからの設定読み込みを統一
  • プロバイダー階層による柔軟な優先度解決
  • 同期・非同期・監視の3つのアクセスパターン
  • ホットリロード、シークレット保護、アクセスログなど本番環境向け機能

VaporやHummingbirdなど主要なサーバーサイドSwiftフレームワークでも統合が進んでおり、今後のSwiftエコシステムにおける設定管理の標準になっていくと思われます。

次回は、SwiftUIの状態管理をマクロで自動化するライブラリ「swift-statable」について解説します。


参考リンク

公式ドキュメント

本記事で紹介したライブラリ

  • swift-env - Swift Configurationのマクロベースラッパー

著者

Discussion