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.
そのような失敗は珍しいものではない。 環境設定 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_2__ と Electron アプリケーションでは、分離はより難しいです。ウェブアセットはネイティブコンテナ内にバンドルされるため、構成ミスは署名されたアーティファクトの一部になり、サーバー上で変更できる値ではなくなります。 より深い問題は構成漂流 .env 、開発、ステージング、および生産環境間の緩やかな分岐です。開発者は 1 つのファイルを更新し、リリースエンジニアは CI 変数を変更し、モバイルビルドは古い値を保管する古いバンドルを保存します。アプリケーションはコンパイルされますが、環境は同じシステムを表すものではありません。__CAPGO_KEEP_0__ アプリケーション間の開発と生産の違いを理解するチームは、明らかなミスを避けることができますが、漂流には運用モデルが必要であり、単にファイル名の命名規則を改善するだけではありません。 differences between development and production in Capacitor apps 目次
環境設定が生産アプリケーションを壊す理由
漂流は無害な例外から始まります
- 目次
- 4つの主な設定パターンを比較する
- 無視できないセキュリティとCI/CDの影響
- CapacitorとElectronで環境設定を実装する
- Simplifying Targeted Updates and Rollbacks with Capgo
- 環境設定チェックリスト
環境設定が生産アプリケーションを壊す理由
最も高価な構成エラーは、構成エラーとして見えにくいことが多い。間違ったAPIベースURLは、認証エラー、空のアカウント画面、支払いエラー、またはネイティブプラグインクラッシュとして表れることがある。インシデントがビルドパイプラインを所有するエンジニアに到達するまで、元のミスは複数のコミットと成功したストアの提出の下に埋もれていたりする。
ハイブリッドアプリケーションには特定の失敗パターンがある。Capacitorはウェブアプリケーションをコンパイルし、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つの層を分離します。
- アプリケーションロジック、環境によって同じまま残すべきです。
- 環境構成、エンドポイント、フラグ、非機密の実行時動作を選択します。
- 機密情報、制御されたストレージに属し、必要に応じてのみインジェクトされるべきです。
その分離により、ドリフトが視覚化されます。また、生産環境が異なる動作を示す場合、生産環境の構成入力を比較することでチームに明確な答えが得られます: 比較することでcodeを非難するのではなく。
4つの主要な構成パターンを比較する
ハイブリッドアプリケーションには、1つの設定パターンが全てに合うものではない。バックエンドは起動時にプロセス環境変数を読み取ることができるが、Capacitor レンダラーには、伝統的なサーバープロセスがない場合もある。Electronは、メインプロセスとレンダラーの間の別の境界を追加する。
パターン1、12要素環境変数
12要素モデルでは、設定を環境固有の入力として扱い、ハードコードされたアプリケーション状態とは区別する。サーバープロセス、コンテナ、CIジョブには自然に当てはまる。サービスは起動時に値を読み取り、同じアーティファクトを複数のデプロイで使用できる。
クライアントサイドアプリはモデルを複雑にする。ブラウザJavaScriptで参照される値は最終的にはクライアントにアクセス可能でなければならないため、環境変数から来た値が秘密であると考えるのは誤りである。パブリックAPIオリジンまたは機能フラグはビルド時置換を使用できるが、意味を持つ特権を持つクレデンシャルは、逆還元可能なクライアントバンドルに送信してはならない。
For Capacitor and Electron, this pattern is best for ビルドオーケストレーションとパブリック設定、秘密保護には適していない。概念上のオーバーヘッドは低いが、実行時変動性は制限される。別の配信レイヤーが存在する場合のみ可能である。
パターン2、環境ごとのビルド
チームは、開発、ステージング、生産用のビルドプロファイルを維持します。各プロファイルは、エンドポイント、アプリケーションID、ネイティブサービスファイル、機能フラグを選択します。アプローチは、プラットフォーム要件と簡単に説明できます。
弱点はアーティファクトの分岐です。3つのビルドには、条件付きコンパイルやプラットフォーム固有のスクリプトがパイプラインに侵入した場合に、特に異なる動作が含まれる可能性があります。各構成変更は別のビルドを作成し、署名、認証、ストア処理、またはマニュアルリリースの調整をトリガーする可能性があります。
ロールバックはアーティファクトの配布とつながっています。古いバイナリに戻すことができますが、ユーザーはすでに異なるバージョンをインストールしている可能性があり、ロールバックのパスは配布チャネルに依存します。
パターン3、実行時構成
実行時構成では、ネイティブアーティファクト外の可変値を移動します。アプリケーションは起動時に構成ドキュメントを取得するか、以前配布されたものをローカルにキャッシュして読みます。これにより、チームはアプリケーションcodeのエンドポイントとフラグを修正することなく、構成を変更できます。
トレードオフは新しい起動依存関係です。リモート構成サービスが利用できない場合、アプリは安全なキャッシュ、バウンドされたタイムアウト、知られているフォールバックポリシーを必要とします。フォールバックは、間違った環境を指すことはできません。ドキュメントのスキーマを検証し、適切な場合はソースを認証し、適用した構成バージョンを記録します。
ハイブリッドアプリケーションでは、非秘密値の場合に最も柔軟なパターンです。ただし、モバイルユーザーがネットワーク接続なしでアプリケーションを起動できるため、オフライン時の注意が必要です。
パターン4:秘密管理用の専用管理
HashiCorp VaultやAWS Secrets Managerなどのプラットフォームは、機密情報の管理を制御するように設計されています。アクセスポリシー、監査トレール、暗号化、ローテーションワークフローをサポートしています。これにより、ユーザーにクレデンシャルを公開しないように、サーバーサイドサービスが機密ストアに認証できるようになります。
これらはクライアント側の秘密問題を解決しません。デバイスの所有者が秘密を検査できるため、モバイルまたはデスクトップクライアントに秘密を配信することは通常、検査されます。クライアントアプリケーションは、秘密を公開する安全な値のみを受け取り、特権的な操作はバックエンドで実行されるようにしてください。
| パターン | ビルドの複雑さ | 再提出が必要なストア | ロールバックのスピード | 最適なもの |
|---|---|---|---|---|
| 12要素変数 | サーバーでは低く、ハイブリッドビルドではモデレート | 通常、バンドルされたクライアント値の場合 | 中等 | バックエンドサービスとパブリックビルド入力 |
| 環境ごとのビルド | 環境が増えると中等から高くなります | 値がバンドルされたときははい | 中等から遅い | リリース頻度が低く小規模なチーム |
| 実行時設定 | 中等 | 互換性のあるウェブ層の変更の場合はいません | バージョン付きペイロードで高速 | ミュータブルなエンドポイント、フラグ、クライアントの動作 |
| 機密管理プラットフォーム | 中程度から高 | バックエンドのみの機密には対応していません | サーバーコンシューマー向けに高速 | バックエンドの特権機密 |
チームが時々リリースする単一アプリケーションを開発している場合は、環境ごとにビルドすることと厳格な検証を組み合わせることができます。並行してステージングとプロダクションを実行する拡大中のチームには、アーティファクトの分散を減らすためにランタイム層が必要です。高頻度のリリースを実施するチームは、ImmutableアプリケーションBundle、ランタイム設定、バックエンドの機密管理を組み合わせる必要があります。 Capacitorの機能フラグ実装ガイド 機能フラグ実装ガイドは、提供されたフラグがスコープ化され、監査され、クライアントに公開される安全である場合にのみ、ランタイム層に組み込まれます。
セキュリティとCI/CDの影響を無視してはなりません
設定値はCIから自動的に安全ではありません。クライアントバンドル、ネイティブリソース、Electronアーカイブ、ログファイル、クラッシュレポート、デバイスバックアップに値が入ると、誰かがそのアーティファクトにアクセスしている場合に、その値を検査できることと想定してください。
パブリックIDとクライアントサイドの設定は機密とは異なります。アプリケーションを識別するのみのモバイルAPIキーが、提供者がそこに期待している場合にのみ、バンドルに含めることができます。データベースのクレデンシャル、署名シークレット、特権トークン、制限なしのサービスクレデンシャルは同じ場所に含めることはできません。OWASP SAMMは、機密のライフサイクルを管理し、機密がリポジトリに含まれないようにすることを推奨しています。

パイプラインの不正な動作
CI/CDシステムは日常的な不正な動作で失敗します。シェルコマンドが変数を展開し、ビルドが失敗すると秘密が例外に含まれます。デバッグステップで環境のダンプが保存されます。ファイルは、リポジトリが不完全なものを受け継いで、バージョン管理システムに入ります。 .env.production 機密情報を含む値を安全なストレージに保存し、パイプラインの権限を狭くしてください。ビルドジョブは、必要な値を受け取り、ログは機密情報をマスクします。生成されたJavaScript、ネイティブリソース、Electronアーカイブ、ソースマップを、誤って含まれる可能性のある機密情報を確認してください。リモートで配信される構成パayloadにチェックサムまたは署名を付けることで、改ざんを検出できますが、クライアントが見える値を機密情報に変えることはできません。 .gitignore.
分析や機密データを扱うチームは、ELECTEのセキュリティホワイトペーパーを使用して、より広範なデータ保護責任をレビューできます。
セキュリティとリリーススピードは共存する必要があります __CAPGO_KEEP_0__ __CAPGO_KEEP_0__
__CAPGO_KEEP_0__
生産用シークレットの安全なパターンは、保護されたストレージ、トランジット中およびリストア中の暗号化、最小限の特権アクセス、およびローテーションです。 変更可能なパブリックエンドポイントの場合、安全なパターンは異なります。 エンドポイントはバージョン管理されたランタイムドキュメントを介して配信され、使用前に検証され、不正値がクローズされるように制限されることができます。
Capacitor または Electron code に特権的な資格情報を入れないでください。 これにより、バックエンドのラウンドトリップを回避できます。 オブフュージョン、ミニファイ、または隠されたレンダラー変数に頼らないでください。 これらのテクニックは、不注意な検査を難しくするだけですが、クライアントデバイスの信頼モデルを変更しません。
実用的なパイプラインは、責任を分離します:
- ソースコントロール: 構成スキーマと安全な例をコミットし、ライブシークレットはコミットしない。
- ビルドステージ: アーティファクトを生成するために必要な値のみをインジェクトし、ログ内でシークレットの拡張を防止します。
- 配信ステージ: 認証された、観察可能なチャネルを介して環境固有のランタイムバンドルを適用します。
- ローテーションステージ: 定義されたスケジュールに基づいてバックエンドの資格情報を無効化し、直ちに無効化するためのインシデントパスを用意します。
The CI/CD secret management practices for Capacitor teams チーム
Implementing Environment Config in Capacitor and Electron
codeとElectronで環境設定を実装する
メンテナブルなセットアップは、1つの構成契約から始まります。フレームワーク固有の条件分岐の山ではなく。安全な環境入力を予測可能なファイルに格納し、ビルドシステムを通じて読み込み、クライアント側アプリケーションに小さな型付きサービスを通じて公開してください。
.env
.env.staging
.env.production
.env.example
src/config/
schema.ts
config-service.ts
capacitor.config.ts
electron/
main.ts
preload.ts
機能するリポジトリレイアウトは次のようになります。 .env.example ソースコントロールに含めるべきものだけが含まれます。残りのファイルは無視し、CIは各ターゲットの値を提供するようにしてください。ファイルにはパブリックエンドポイントや機能フラグが含まれるかもしれませんが、機密なバックエンドクレデンシャルは専用のシークレットストアに残し、クライアントバンドルの一部にはならないようにしてください。
1つの契約を定義して検証する
Viteを使用すると、クライアント側で公開される変数は通常、prefixで始まります。そのprefixは可視性の信号であり、セキュリティの境界ではありません。 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 | Electron |
|---|---|---|
| メイン構成境界 | ネイティブプロジェクトとバンドルされたウェブアセット | メインプロセス、プレロード、レンダラー |
| 安全なクライアント値 | パブリックエンドポイントとフラグ | プレロードを通じて渡されたパブリックエンドポイントとフラグ |
| 敏感なクレデンシャル | アプリケーションバンドルから外す | パッケージされたアーカイブから外す |
| 一般的なエラー | ネイティブ同期後、古いビルド値 | process.env レンダラーでは利用できない |
| 実行時更新パス | 署名されたウェブバンドルまたはリモート設定 | 署名されたウェブバンドルまたは制御されたアプリケーション更新 |
最も一般的な実装ミスは、ファイルが自動的にプライベートであると仮定することです。バンドラーは生成されたJavaScriptに値を含めることができ、パッケージングステップではファイル自体を含めることができます。ソースツリーのみを検査するのではなく、最終的なアーティファクトを検査してください。 .env __CAPGO_KEEP_0__を使用した簡素化されたターゲットアップデートとロールバック
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_0__エンドポイントが予期せずに変更された場合、チームは設定ソースを更新し、Webバンドルをビルドし、生産性チャンネルに公開するのではなく、ネイティブストアのリリースを待つ必要がなくなる。重要な境界は維持される: このアプローチは、ネイティブ__CAPGO_KEEP_1__のプラットフォーム規則をバイパスせず、秘密を安全に配布することもない。ただし、互換性のあるWeb層の設定を修正するのにかかる時間が短縮される。
チャンネルは環境の所有権を明確にする
ロールバックも同等の重要性があります。新しい構成が不健康なサービスを指している場合、リリースオペレータはそのチャンネルに対して、前の知られている良好なバンドルを選択できるようにする必要があります。バージョン履歴、デプロイガードレール、デバイスレベルレポートは、問題が広範囲にわたっているか、ロールアウトセグメントに限られているかをチームが判断するのに役立ちます。
結果として得られるのは、より明確なプロモーションパスです。
- 開発用にバンドルをビルドして検証する。
- 同じテスト済みコンテンツをステージングにプロモートする。
- プロダクションチャンネルアップデートを承認する。
- 採用と失敗を監視する。
- 構成が不正に動作する場合、チャンネルをリバートする。
そのプロセスは、各エンドポイント修正に対して緊急のネイティブビルドを作成する誘惑を減らすことで、特に Capgo バージョン管理とロールバックワークフロー 環境固有のリリースが必要なチームにとって、追跡可能な履歴を失うことなく特に重要です。
環境構成アウディットチェックリスト
毎回のメジャーリリースとパイプラインの変更後にこのアウディットを実行する必要があります。
- アーティファクトの検査: コミットされたファイル、生成されたJavaScript、ネイティブリソース、ソースマップ、またはElectronアーカイブに秘密情報が表示されないことを確認します。
- 環境の分離: 開発、ステージング、および生産環境が異なるエンドポイント、識別子、および承認されたキーを使用することを確認します。
- 入力の保護: すべての
.envバリアントは無視され、必要なスキーマが記載されていることを確認します。.env.exampleCIのレビュー: - パイプラインは、開発者ローカルマシンに依存せずに、コントロールストアから値をインジェクトすることを確認します。 復旧テスト:
- ランタイム構成が、必要な値が欠落した場合に迅速に失敗し、ネイティブシェルを再構築せずに互換性のあるロールバックが可能であることを確認します。 Inspect artifacts:

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