You’ve shipped the release, signed the native binary, and watched the production rollout start normally. Then support reports that users can’t complete a purchase. The crash log looks unrelated, so you spend hours tracing requests, plugin initialization, and recent JavaScript changes. The cause turns out to be a staging API URL left in a rushed production build.
リリースを出荷した後、ネイティブバイナリに署名し、正常にプロダクションロールアウトを開始した後、サポートはユーザーが購入を完了できないことを報告します。クラッシュログは関係ないように見えますので、リクエスト、プラグインの初期化、最近のJavaScriptの変更を追跡するのに数時間を費やします。原因は、急いでプロダクションビルドに残したステージング__CAPGO_KEEP_0__URLが原因でした。 環境設定 is the discipline of keeping deployment-specific settings, such as API endpoints, feature flags, database credentials, and third-party keys, separate from application code. In Capacitor and Electron apps, the separation is harder because web assets are bundled inside native containers, so a configuration mistake can become part of a signed artifact rather than a value you can change on the server.
__CAPGO_KEEP_1__アプリケーションでは、設定ミスが署名済みアーティファクトの一部になるのではなく、サーバー上で変更できる値になります。 より深い問題は設定の漂流 .env 、開発、ステージング、生産環境間の漸次的な差異です。 differences between development and production in Capacitor apps 開発と生産環境の違いを理解しているチームは、__CAPGO_KEEP_0__アプリケーションでは明らかなミスを回避できますが、漂流には運用モデルが必要です。
実際の質問は簡単です: 同じコードベースを複数の環境に配信する方法はありますか? また、再構築、署名、または各設定変更ごとにネイティブアプリを提出する必要はありませんか?
目次
- 環境設定が生産アプリケーションを壊す理由
- 4つの主な設定パターンを比較する
- 無視できないセキュリティとCI/CDの影響
- CapacitorとElectronで環境設定を実装する
- Simplifying Targeted Updates and Rollbacks with Capgo
- 環境設定のチェックリスト
環境設定が生産アプリケーションを壊す理由
最も高価な構成エラーは、ほとんどの場合、構成エラーとして見えません。間違ったAPIベースURLは、認証エラー、空のアカウント画面、支払いエラー、またはネイティブプラグインクラッシュとして表面化することがあります。エラーがビルドパイプラインを所有するエンジニアに到達するまで、元のミスは複数のコミットと成功したストアの提出の下に埋もれていました。
ハイブリッドアプリケーションには特定のエラーのパターンがあります。CapacitorはWebアプリケーションをコンパイルし、iOSまたはAndroidプロジェクトにアセットを配置します。Electronはレンダラーとメインプロセスのcodeをデスクトップアプリケーションにパッケージ化します。エンドポイントまたは機能フラグがビルド中に解決されると、その結果の値はアーティファクトと共に移動します。後で変更すると、通常、新しいバンドルを生成し、署名し、適用可能なチャンネルを通じて配布する必要があります。
ドリフトは無害な例外から始まります
構成ドリフトは、妥当なショートカットから成長します:
- ローカルオーバーライド: 開発者は機能をブロックするためにテストエンドポイントをハードコードし、取り除くことを忘れています。
- 別のパイプライン変数: CIは、リポジトリのドキュメントされた設定と一致しない生産性の値を使用します。
- ネイティブのみの設定: Android、iOS、Electronは異なるプラグイン識別子またはコールバック設定を受け取ります。
- 未文書化のフラグ: オペレーションは、デプロイメントシステムで直接機能フラグを変更し、ステージングは古い動作を引き続き使用します。
各選択肢は独立して機能できます。問題は、誰もが、どの値が権威があり、どの環境が所有し、最後に変更されたかを判断できなくなることです。
実用的なルール: If a configuration value can change independently of application logic, treat it as a deployment input, not as source code.
ステージング環境は、生産性に近いようにする必要があります。ただし、孤立したエンドポイント、クレデンシャル、データを使用する必要があります。環境が異なる場合、ステージングは有用なリハーサルとして機能しません。リリースは、あるセットの仮定に対してすべてのテストを通過し、別のセットの仮定に対して即座に失敗する可能性があります。
ビルド時設定はリリースのボトルネックになります。
ビルド時設定は有用です。公開可能なコンパイル時値、プラットフォーム固有の識別子、ネイティブツールの必要な設定は、実行可能ファイルがパッケージ化される前に存在する必要があります。問題は、オペレーションがリリース後に変更できる値をビルド時インジェクションで使用することです。
生産環境のAPIが新しいエンドポイントに移行した場合、伝統的なCapacitorワークフローでは、チームは値を変更し、Webアセットをビルドし、ネイティブプロジェクトを同期し、アプリケーションを署名し、プラットフォームのリリースプロセスを通じて配布します。Electronチームは、変更された値がパッケージされたアプリケーション内に含まれる場合に似たサイクルを経験します。
そのワークフローは、意図的な製品リリースには適していますが、急いでいる設定の修正には不適切です。バイナリは正常であり、JavaScriptは変更されていないのに、単に1つの文字列が完全な配信サイクルを強制します。
より安全な設計では、3つの層を分離します。
- アプリケーションロジック環境設定
- 非機密のランタイム動作を選択するエンドポイントやフラグを選択します。機密情報
- コントロールされたストレージに保管し、必要に応じてのみインジェクトするものです。その分離により、ドリフトが視覚化されます。また、生産環境が異なる動作を示した場合、チームは明確な答えを得ることができます: 比較する設定入力値を確認し、__CAPGO_KEEP_0__を非難するのではなく。
That separation makes drift visible. It also gives the team a clear answer when production behaves differently: compare the configuration inputs before blaming the code.
Application logic
ハイブリッドアプリケーションには、すべての部分に合う単一の構成パターンはありません。バックエンドでは、起動時にプロセス環境変数を読み取ることができますが、Capacitor レンダラーには、伝統的なサーバープロセスがない場合があります。Electronは、メインプロセスとレンダラー間の別の境界を追加します。正しい選択肢は、値がパブリック、機密、リリース後変更可能、またはネイティブビルドツールによって必要であるかどうかにかかっています。
パターン1、12要素環境変数
12要素モデルでは、構成を環境固有の入力として扱います。アプリケーション状態としてハードコードするのではなく、サーバープロセス、コンテナ、CIジョブに自然に適しています。サービスは起動時に値を読み取り、同じアーティファクトを複数のデプロイメントで使用できます。
クライアントサイドアプリはモデルを複雑にします。ブラウザのJavaScriptが参照する値は、最終的にはクライアントにアクセスできる必要があるため、環境変数から受け取られた値だけが機密であると考えるべきではありません。パブリックAPIオリジンまたは機能フラグはビルド時_substitutionを使用できますが、意味を持つ特権を持つ資格情報は、逆還元可能なクライアントバンドルに送信してはなりません。
For Capacitor and Electron, this pattern is best for ビルドオーケストレーションとパブリック構成機密情報を保護するには適していません。概念上のオーバーヘッドは低いですが、実行時での変更可能性は制限されます。別の配信レイヤーが存在する場合に限ります。
パターン2、環境ごとのビルド
チームは開発、ステージング、生産用のビルドプロファイルを維持します。各プロファイルはエンドポイント、App ID、ネイティブサービスファイル、機能フラグを選択します。アプローチはプラットフォームの要件と簡単に説明できます。
弱点はアーティファクトの分岐です。3つのビルドには異なる動作が含まれるだけでなく、異なる設定が含まれる場合があります。特に条件付きコンパイルやプラットフォーム固有のスクリプトがパイプラインに侵入する場合です。各構成変更は別のビルドを作成し、署名、認証、ストア処理、またはマニュアルリリースの調整をトリガーする可能性があります。
ロールバックはアーティファクトの配布とつながっています。古いバイナリに戻すことができますが、ユーザーはすでに異なるバージョンをインストールしている可能性があり、ロールバックのパスは配布チャネルに依存します。
パターン3、実行時構成
Runtime configuration moves mutable values outside the native artifact. The application retrieves a configuration document on launch or reads a locally cached document that was previously delivered. This lets teams correct endpoints and flags without changing application code.
取引は新しい起動依存関係です。リモート構成サービスが利用できない場合、アプリは安全なキャッシュ、バウンドされたタイムアウト、知られているフォールバックポリシーが必要です。フォールバックは間違った環境を指すことはできません。ドキュメントのスキーマを検証し、適切な場合はソースを認証し、適用した構成バージョンを記録します。
ハイブリッドアプリケーションでは、非秘密値の場合、このパターンは通常最も柔軟なものです。ただし、オフライン時の動作に注意が必要です。モバイルユーザーは、ネットワーク接続なしでアプリケーションを起動できます。
パターン4:秘密管理用の専用管理
HashiCorp VaultやAWS Secrets Managerなどのプラットフォームは、機密情報の管理を制御するように設計されています。アクセスポリシー、監査トレイル、暗号化、ローテーションワークフローをサポートしています。これにより、サーバーサイドサービスが秘密ストアに認証することなく、ユーザーにクレデンシャルを公開することなく、機密情報を管理できます。
これらはクライアント・シークレットの問題を解決しません。デバイスの所有者が機密情報を検査できるため、デバイスに機密情報を送信することは避けるべきです。クライアントアプリケーションは、機密情報を公開することなく、有効な値を受信する必要があります。特権的な操作は、バックエンドで実行されるべきです。
| パターン | ビルドの複雑さ | 再提出が必要なストア | ロールバックのスピード | 最適なもの |
|---|---|---|---|---|
| 12要素変数 | サーバーでは低く、ハイブリッドビルドでは普通 | 通常、バンドルされたクライアント値の場合 | 中等 | バックエンドサービスとパブリックビルド入力 |
| 環境ごとのビルド | 環境が増えるにつれて中等から高 | 値がバンドルされた場合 | 中等から遅い | リリース頻度が低い小規模チーム |
| 実行時設定 | 中等 | 互換性のあるウェブ層の変更の場合 | バージョン付のペイロードとともに高速 | 可変エンドポイント、フラグ、クライアントの動作 |
| 機密管理プラットフォーム | 中程度から高 | バックエンドのみの機密には使用しない | サーバーコンシューマー向けに高速 | バックエンドの特権機密 |
チームが時々リリースする単一アプリケーションに取り組む場合、環境毎のビルドに加えて厳密な検証を開始できます。並行してステージングとプロダクションを取り組む成長中のチームには、アーティファクトの分散を減らすためにランタイム層が必要です。高頻度のチームは、Immutableアプリケーションバンドル、ランタイム設定、バックエンドの機密管理者を組み合わせる必要があります。 feature flag implementation guidance for Capacitor ランタイム層に組み込まれているが、フラグがスコープ化され、監査され、クライアントに公開される安全であることを保証する必要があります。
セキュリティとCI/CDの影響を無視することはできません。
設定値はCIから自動的に安全ではありません。クライアントバンドル、ネイティブリソース、Electronアーカイブ、ログファイル、クラッシュレポート、デバイスバックアップに値が入り、誰かがそのアーティファクトにアクセスできる場合、その値を検査できることと想定してください。
パブリックIDとクライアントサイドの設定は機密とは異なります。モバイルAPIキーがアプリケーションを識別するためにのみ使用され、提供者がそこに期待し、その使用を制限している場合、バンドル内で許容されるかもしれません。データベースクレデンシャル、署名シークレット、特権トークン、制限なしのサービスクレデンシャルは同じ場所に安全ではありません。OWASP SAMMは、責任の分離またはプロダクション機密の暗号化を推奨し、保護されていない機密がリポジトリに侵入しないようにし、そのライフサイクルを管理するのではなく、インシデントを待つのではなくします。

パイプラインが設定情報を漏らす場所
CI/CDシステムは日常的な方法で失敗する。シェルコマンドが変数を展開し、エラーが秘密を含む例外を生成したり、デバッグステップで環境のダンプをアーカイブしたりする。 .env.production ファイルは、リポジトリが不完全なものを受け継いでいる場合にバージョン管理システムに追加されることもある。 .gitignore.
機密情報を安全に保存し、パイプラインの権限を狭くしておく。ビルドジョブは、目的のターゲットに必要な値だけを受け取り、ログはそれらをマスクする。生成されたJavaScript、ネイティブリソース、Electronアーカイブ、ソースマップを含む不注意な包含を確認する。リモートで配信された構成パayloadにチェックサムまたは署名を付けることで、改ざんを検出するのに役立つが、クライアントに表示される値を秘密にするには十分ではない。
分析やその他の機密データを扱うチームは、ELECTEのセキュリティホワイトペーパーを使用してAI分析をレビューすることができる。 セキュリティはリリーススピードと共存しなければならない。 CI/CDパイプラインにおけるセキュリティリスクの3つの段階を示す図。
パイプラインが設定情報を漏らす場所
生産用シークレットの安全なパターンは、コントロールされたストレージ、トランジットとリストアの暗号化、最小限の特権アクセス、ローテーションです。 変更可能なパブリックエンドポイントの場合、安全なパターンは異なります。 エンドポイントはバージョン管理されたランタイムドキュメントを通じて配信され、使用前に検証され、不正値がクローズされるように制限されることができます。
Capacitor または Electron code に特権的な資格情報を入れないでください。 これにより、バックエンドのラウンドトリップを回避できます。 オブフュージョン、ミニファイション、または隠れたレンダラー変数に頼るのではなく、資格情報を安全に保管してください。
実用的なパイプラインは、責任を分離します:
- ソース管理: 構成スキーマと安全な例をコミットし、ライブシークレットは含めないでください。
- ビルドステージ: アーティファクトを生成するために必要な値のみをインジェクトし、ログでシークレットの拡大を防ぎます。
- 配信ステージ: 認証された、観察可能なチャネルを通じて環境固有のランタイムバンドルを適用します。
- ローテーションステージ: 定義されたスケジュールに基づいてバックエンド資格情報を無効化し、直ちに無効化するためのインシデントパスを用意します。
The CI/CD secret management practices for Capacitor teams は、明示的なインベントリと組み合わせると最も有効です。各変数について、公開か機密か、所有者、使用する環境、変更がネイティブのビルドを必要とするかどうかを文書化してください。
CapacitorとElectronで環境設定を実装する
A maintainable setup starts with one configuration contract, not a pile of framework-specific conditionals. Keep safe environment inputs in predictable files, load them through the build system, and expose them to application code through a small typed service.
作業可能なリポジトリレイアウトは次のようになります。
.env
.env.staging
.env.production
.env.example
src/config/
schema.ts
config-service.ts
capacitor.config.ts
electron/
main.ts
preload.ts
ソースコントロールに含めるべきものだけが含まれます。残りのファイルは無視し、CIは各ターゲットの値を提供するようにしてください。ファイルにはパブリックエンドポイントや機能フラグが含まれるかもしれませんが、機密のバックエンドクレデンシャルは専用のシークレットストアに格納し、クライアントバンドルの一部にはならないようにしてください。 .env.example 1つの契約を定義して検証する
Viteを使用すると、クライアント側に公開される変数は通常、prefixで始まります。そのprefixは可視性のシグナルであり、セキュリティの境界ではありません。
__CAPGO_KEEP_0__の起動時に呼び出す VITE_ 値が欠けている場合、明確なエラーを生成するようにしてください。そうしないと、ローカルエンドポイントを選択することによって生じる可能性のある大量の生産ミールートのバグを防ぐことができます。
// src/config/schema.ts
export type AppConfig = {
apiBaseUrl: string
enableNewCheckout: boolean
environment: 'development' | 'staging' | 'production'
}
function required(name: string, value: string | undefined): string {
if (!value) {
throw new Error(`Missing required configuration: ${name}`)
}
return value
}
export function loadConfig(): AppConfig {
const environment = required('VITE_APP_ENV', import.meta.env.VITE_APP_ENV)
if (!['development', 'staging', 'production'].includes(environment)) {
throw new Error(`Unsupported environment: ${environment}`)
}
return {
apiBaseUrl: required('VITE_API_BASE_URL', import.meta.env.VITE_API_BASE_URL),
enableNewCheckout: import.meta.env.VITE_ENABLE_NEW_CHECKOUT === 'true',
environment: environment as AppConfig['environment'],
}
}
__CAPGO_KEEP_0__ loadConfig() __CAPGO_KEEP_0__
ローカル開発では、Viteは適切なファイルを選択するモードで動作します。ステージングビルドでは .env.stagingを使用し、プロダクションビルドでは .env.productionを使用します。CIジョブでは、モードを明示的に設定する必要があります。開発者がローカルで使用したものを継承するのではなく。
Capacitorネイティブ設定
ネイティブプロジェクトでは、環境固有の識別子、サービスファイル、プラグイン設定などが必要になることがよくあります。 capacitor.config.ts__CAPGO_KEEP_0__に値を保持するようにしてくださいが、プライベートクレデンシャルを置くのは避けるべきです。
// capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli'
const isProduction = process.env.APP_ENV === 'production'
const config: CapacitorConfig = {
appId: isProduction ? 'com.example.app' : 'com.example.app.staging',
appName: isProduction ? 'Example' : 'Example Staging',
webDir: 'dist',
plugins: {
PushNotifications: {
presentationOptions: ['badge', 'sound', 'alert'],
},
},
}
export default config
ファイアベースファイル、プッシュノーティフィケーション証明書、プラットフォーム識別子などは、ネイティブビルドパイプラインによって選択され、適切なアクセス制御とともに保存されるべきです。プロダクションアプリは、ステージングサービスクレデンシャルを再利用するべきではなく、両方のビルドがコンパイルされるからです。
__CAPGO_KEEP_0__ Capacitor local environment setup guide はチームがローカルモードを標準化するのに役立ちますが、リポジトリには明示的な契約とCI検証が必要です。
Electronではプロセス境界が必要です。
ElectronのレンダラーはNode.jsのメインプロセスと同じではありません。ハード化されたアプリケーションでは process.env メインプロセスでは利用可能かもしれませんが、レンダラーでは未定義または意図的に利用できない場合があります。安全な構成のみをプレロードブリッジを通じて渡してください。
// electron/main.ts
import { app, BrowserWindow } from 'electron'
import path from 'node:path'
function createWindow() {
const window = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
},
})
const safeConfig = {
apiBaseUrl: process.env.API_BASE_URL,
environment: process.env.APP_ENV,
}
window.webContents.on('did-finish-load', () => {
window.webContents.send('app-config', safeConfig)
})
return window
}
app.whenReady().then(createWindow)
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('appConfig', {
get: () => new Promise((resolve) => {
ipcRenderer.once('app-config', (_event, config) => resolve(config))
}),
})
レンダラーでオブジェクトを再度検証してください。ブリッジは、秘密のストアトークンや特権ファイルシステムの機能性を公開してはなりません。
| アスペクト | Capacitor | Capacitor |
|---|---|---|
| エレクトロン | メイン構成境界 | ネイティブプロジェクトとバンドルされたウェブアセット |
| メインプロセス、プレロード、レンダラー | 安全なクライアント値 | 公開エンドポイントとフラグ |
| プレロードを通じて渡された公開エンドポイントとフラグ | アプリケーションバンドルから外す | パッケージされたアーカイブから外す |
| 一般的なエラー | ネイティブの同期後、古いビルド値 | process.env レンダラーでは利用できない |
| 実行時更新パス | 署名されたウェブバンドルまたはリモート設定 | 署名されたウェブバンドルまたは制御されたアプリケーション更新 |
最も一般的な実装ミスは、ファイルが自動的にプライベートであると仮定することです。バンドラーは生成されたJavaScriptに値を含めることができ、パッケージングステップではファイル自体を含めることができます。ソースツリーのみを検査するのではなく、最終的なアーティファクトを検査してください。 .env ターゲットされた更新とロールバックの簡素化
Simplifying Targeted Updates and Rollbacks with Capgo
__CAPGO_KEEP_0__
Capgoのリアルタイム更新モデルはそのギャップを埋める ターゲットチャンネル 開発、ステージング、または本番環境などの展開階層に対応

Consider a production API endpoint that changes unexpectedly. The team can update the configuration source, build the web bundle, and publish it to the production channel instead of waiting for a native store release. The important boundary remains intact: this approach doesn’t bypass platform rules for native code, and it doesn’t make a secret safe to ship. It does reduce the time required to correct compatible web-layer configuration.
本番__CAPGO_KEEP_1__エンドポイントが予期せずに変更になった場合、チームは構成ソースを更新し、Webバンドルをビルドし、本番チャンネルに公開することができます。ネイティブ__CAPGO_KEEP_1__のプラットフォーム規則をバイパスすることなく、秘密を安全に配信することなく、互換性のあるWeb層の構成を修正するのにかかる時間を短縮できます。
チャンネルは環境の所有権を明確にする
ロールバックも同等の重要性があります。新しい構成が不健康なサービスを指している場合、リリースオペレータはそのチャネルで使用できる前の知られている良好なバンドルを選択できるようにする必要があります。バージョン履歴、デプロイガードレール、デバイスレベルレポートは、問題が広範囲にわたっているか、ロールアウトセグメントに限定されているかをチームが判断するのに役立ちます。
結果は、より明確なプロモーションパスが得られます。
- 開発用にバンドルをビルドして検証する。
- 同じテスト済みコンテンツをステージングにプロモートする。
- プロダクションチャネル更新を承認する。
- 採用と失敗を監視する。
- チャネルが不正に動作する場合に構成をリバートする。
そのプロセスは、エンドポイントの修正ごとに緊急のネイティブビルドを作成する誘惑を減らします。 Capgo バージョン管理とロールバックワークフロー 特に、環境固有のリリースが必要なチームにとって、追跡可能な履歴を失うことなく、特に環境固有のリリースが必要なチームにとっては、特別に適切です。
環境構成チェックリスト
毎回のメジャーリリースとパイプラインの変更後には、このチェックリストを実行する必要があります。
- アーティファクトの検査: コミットされたファイル、生成されたJavaScript、ネイティブリソース、ソースマップ、またはElectronアーカイブに秘密情報が表示されないことを確認します。
- 環境の分離: 開発、ステージング、および生産環境が異なるエンドポイント、識別子、および承認されたキーを使用することを確認します。
- 入力の保護: すべての
.envバリアントは無視され、必要なスキーマが記載されていることを確認します。.env.exampleCIのレビュー: - パイプラインは、開発者のローカルマシンに依存せずに、コントロールされたストアから値をインジェクトすることを確認します。 復旧テスト:
- ランタイム構成が、必要な値が欠落した場合に迅速に失敗し、ネイティブシェルを再構築せずに互換性のある更新をロールバックできることを確認します。 環境構成の設定

完全なアクセスが可能になるのは、誰でもプロダクション設定値のすべてのオーナー、ソース、スコープ、ロールバック手順を特定できるようになる時です。
CapgoはCapacitorJSとElectronアプリ向けに署名されたライブアップデートを提供し、ターゲットチャンネルとバージョンロールバックを含む、互換性のあるJavaScript、CSS、設定、資産の変更に対応しています。リビルドサイクルを削減し、環境の更新を制御したい場合は、 Capgo を確認してください。また、既存のCI/CDプロセスと併せて評価してください。