ऐसे एनवायरनमेंट कॉन्फ़िगरेशन पैटर्न जो वेब, बैकएंड और मोबाइल में URLs, कीज़, और फीचर फ्लैग्स को कोड से अलग रखकर dev, staging और prod में समस्याएं घटाते हैं।

पहले दिन हार्डकोडेड कॉन्फ़िग ठीक लगती है। फिर आपको एक staging वातावरण चाहिए होता है, दूसरा API, या एक त्वरित फीचर स्विच — और वह “सरल” बदलाव रिलीज़ जोखिम बन जाता है। समाधान सीधा है: वातावरण के मान सोर्स फाइलों से बाहर रखें और उन्हें एक अनुमान्य सेटअप में रखें।
आम परेशानियाँ आसानी से दिख जाती हैं:
“बस प्रोड के लिए बदल दो” एक आदत बनाती है कि आखिरी मिनट में संपादन कर दिए जाएँ। ये बदलाव अक्सर रिव्यू, टेस्ट और रिपीटेबलिटी को स्किप कर देते हैं। एक आदमी URL बदलता है, दूसरा की बदलता है, और अब आप एक बुनियादी सवाल का उत्तर नहीं दे पाते: इस बिल्ड के साथ कौन-सा सटीक कॉन्फ़िग शिप हुआ था?
एक सामान्य परिदृश्य: आप एक नया मोबाइल वर्जन staging के खिलाफ बनाते हैं, फिर किसी ने रिलीज़ से ठीक पहले URL को prod पर प्वाइंट कर दिया। अगले दिन बैकएंड फिर बदलता है और आपको रोलबैक करना पड़ता है। अगर URL हार्डकोडेड है, तो रोलबैक का मतलब फिर से एक ऐप अपडेट है। यूज़र इंतज़ार करते हैं और सपोर्ट टिकट बढ़ जाते हैं।
यहाँ लक्ष्य एक सरल स्कीम है जो web, Go बैकएंड और Flutter मोबाइल ऐप में काम करे:
Dev, staging, और prod को एक ही ऐप के तीन अलग-अलग स्थानों पर चलने जैसा महसूस होना चाहिए। उद्देश्य व्यवहार बदलना नहीं, केवल मान बदलना है।
क्या बदलना चाहिए: वह सब कुछ जो उस जगह से जुड़ा हो जहाँ ऐप चल रहा है या कौन इसका उपयोग कर रहा है — बेस URL और होस्टनेम, क्रेडेंशियल्स, सैंडबॉक्स बनाम रीयल इंटीग्रेशन, और सुरक्षा नियंत्रण जैसे कि प्रोड में अधिक कड़े लॉगिंग या सेटिंग्स।
क्या समान रहना चाहिए: लॉजिक और भागों के बीच का कॉन्ट्रैक्ट। API रूट्स, रिक्वेस्ट/रेस्पॉन्स शेप्स, फीचर नाम और कोर बिज़नेस नियम वातावरण के हिसाब से अलग नहीं होने चाहिए। अगर staging अलग व्यवहार करता है, तो वह प्रोडक्शन के लिए विश्वसनीय रिहर्सल नहीं रह जाता।
“नया वातावरण” बनाम “नया कॉन्फ़िग वैल्यु” के लिए व्यावहारिक नियम: एक नया वातावरण तभी बनाएं जब आपको एक अलग सिस्टम चाहिए (अलग डेटा, एक्सेस और जोखिम)। अगर आपको केवल अलग endpoints या विभिन्न मान चाहिए, तो एक कॉन्फ़िग वैल्यु जोड़ें।
उदाहरण: आप नया सर्च प्रोवाइडर टेस्ट करना चाहते हैं। अगर इसे छोटे समूह के लिए चालू करना सुरक्षित है, तो एक ही staging रखें और फीचर फ्लैग जोड़ें। अगर इसके लिए अलग डेटाबेस और सख्त एक्सेस कंट्रोल चाहिए, तो तब नया वातावरण समझदारी है।
एक अच्छा सेटअप एक बात अच्छी तरह से करता है: यह गलती से dev URL, टेस्ट की या अधूरी फीचर शिप करने को कठिन बनाता है।
हर ऐप (web, backend, mobile) के लिए एक ही तीन लेयर्स का उपयोग करें:
भ्रम से बचने के लिए, प्रति ऐप एक सिंगल सोर्स ऑफ ट्रुथ चुनें और उसी पर टिकें। उदाहरण के लिए, बैकएंड स्टार्टअप पर environment variables पढ़ता है, वेब ऐप बिल्ड-टाइम वेरिएबल्स या एक छोटे runtime config फ़ाइल से पढ़ता है, और मोबाइल ऐप बिल्ड टाइम पर चुने गए छोटे environment फ़ाइल से पढ़ता है। हर ऐप के अंदर स्थिरता एक-दूसरे पर ज़ोर देने से ज़्यादा मायने रखती है।
एक सरल, पुन:उपयोग योग्य स्कीम इस तरह दिखती है:
हर कॉन्फ़िग आइटम को एक स्पष्ट नाम दें जो तीन सवालों का जवाब दे: यह क्या है, कहाँ लागू होता है, और किस प्रकार का है।
एक व्यावहारिक कन्वेंशन:
इस तरह किसी को अनुमान नहीं लगाना पड़ेगा कि "BASE_URL" React ऐप के लिए है, Go सर्विस के लिए है, या Flutter ऐप के लिए।
React कोड ब्राउज़र में चलता है, इसलिए जो कुछ आप भेजते हैं वह पढ़ा जा सकता है। लक्ष्य सरल है: सीक्रेट्स सर्वर पर रखें, और ब्राउज़र को केवल सुरक्षित सेटिंग्स पढ़ने दें जैसे API base URL, ऐप नाम, या नॉन-सेंसिटिव फीचर फ्लैग।
बिल्ड-टाइम कॉन्फ़िग तब इंजेक्ट होता है जब आप बंडल बनाते हैं। यह उन मानों के लिए ठीक है जो शायद ही बदलते हैं और एक्सपोज़ होने के लिए सुरक्षित हैं।
रनटाइम कॉन्फ़िग तब लोड होती है जब ऐप शुरू होता है (उदाहरण के लिए, ऐप के साथ सर्व की जाने वाली एक छोटी JSON फ़ाइल से या एक इंजेक्टेड ग्लोबल से)। यह उन मानों के लिए बेहतर है जिन्हें आप डिप्लॉय के बाद बदलना चाहें, जैसे एनवायरनमेंट के बीच API बेस URL बदलना।
एक सरल नियम: अगर इसे बदलने के लिए UI को फिर से बिल्ड नहीं करना चाहिए, तो इसे runtime बनाएं।
डेव के लिए लोकल फाइल रखें (gitignored) और असली मान अपनी deploy पाइपलाइन में सेट करें।
.env.local (gitignored) में VITE_API_BASE_URL=http://localhost:8080VITE_API_BASE_URL को environment variable के रूप में सेट करें, या उसे deploy के समय बनाई गई runtime config फ़ाइल में डालेंरनटाइम उदाहरण (आपके ऐप के पास सर्व की गई):
{ "apiBaseUrl": "https://api.staging.example.com", "features": { "newCheckout": false } }
फिर इसे स्टार्टअप पर एक बार लोड करें और एक ही जगह रखें:
export async function loadConfig() {
const res = await fetch('/config.json', { cache: 'no-store' });
return res.json();
}
React env vars को सार्वजनिक समझें। पासवर्ड, प्राइवेट API कीज़, या डेटाबेस URLs को वेब ऐप में न रखें।
सुरक्षित उदाहरण: API base URL, Sentry DSN (public), बिल्ड वर्ज़न, और साधारण फीचर फ्लैग्स।
बैकएंड कॉन्फ़िग तब सुरक्षित रहता है जब वह टाइप किया हुआ हो, environment variables से लोड हो और सर्वर ट्रैफ़िक स्वीकार करने से पहले वेलिडेट हो।
शुरूआत करें यह तय करके कि बैकएंड को चलाने के लिए क्या चाहिए, और उन मानों को स्पष्ट बनाएं। सामान्य "जरूरी" मान:
APP_ENV (dev, staging, prod)HTTP_ADDR (उदाहरण: :8080)DATABASE_URL (Postgres DSN)PUBLIC_BASE_URL (callbacks और लिंक्स के लिए)API_KEY (किसी थर्ड-पार्टी सर्विस के लिए)फिर उन्हें एक struct में लोड करें और अगर कुछ गायब या गलत हो तो फेल फ़ास्ट करें। इस तरह आप सेकंड में समस्याएँ ढूंढ लेते हैं, आंशिक डिप्लॉय के बाद नहीं।
package config
import (
"errors"
"net/url"
"os"
"strings"
)
type Config struct {
Env string
HTTPAddr string
DatabaseURL string
PublicBaseURL string
APIKey string
}
func Load() (Config, error) {
c := Config{
Env: mustGet("APP_ENV"),
HTTPAddr: getDefault("HTTP_ADDR", ":8080"),
DatabaseURL: mustGet("DATABASE_URL"),
PublicBaseURL: mustGet("PUBLIC_BASE_URL"),
APIKey: mustGet("API_KEY"),
}
return c, c.Validate()
}
func (c Config) Validate() error {
if c.Env != "dev" && c.Env != "staging" && c.Env != "prod" {
return errors.New("APP_ENV must be dev, staging, or prod")
}
if _, err := url.ParseRequestURI(c.PublicBaseURL); err != nil {
return errors.New("PUBLIC_BASE_URL must be a valid URL")
}
if !strings.HasPrefix(c.DatabaseURL, "postgres://") {
return errors.New("DATABASE_URL must start with postgres://")
}
return nil
}
func mustGet(k string) string {
v, ok := os.LookupEnv(k)
if !ok || strings.TrimSpace(v) == "" {
panic("missing env var: " + k)
}
return v
}
func getDefault(k, def string) string {
if v, ok := os.LookupEnv(k); ok && strings.TrimSpace(v) != "" {
return v
}
return def
}
यह डेटाबेस DSNs, API कीज़ और callback URLs को कोड और गिट से बाहर रखता है। होस्टेड सेटअप में, आप इन env vars को प्रति वातावरण इंजेक्ट करते हैं ताकि dev, staging और prod बिना कोई लाइन बदले अलग रह सकें।
Flutter ऐप्स आमतौर पर दो लेयर कॉन्फ़िग चाहते हैं: बिल्ड-टाइम फ्लेवर्स (जो आप भेजते हैं) और रनटाइम सेटिंग्स (जो ऐप बिना नए रिलीज़ के बदल सकता है)। इन्हें अलग रखने से “बस एक URL बदलना” आपातकालीन रीबिल्ड में नहीं बदलता।
तीन फ्लेवर्स बनाएं: dev, staging, prod। फ्लेवर्स उन चीज़ों को नियंत्रित करें जो बिल्ड टाइम पर फिक्स होनी चाहिए, जैसे ऐप नाम, bundle id, साइनिंग, analytics प्रोजेक्ट, और whether debug tools enabled हैं।
फिर केवल गैर-संवेदनशील डिफ़ॉल्ट --dart-define (या आपकी CI) के साथ पास करें ताकि आप उन्हें कोड में हार्डकोड न करें:
ENV=stagingDEFAULT_API_BASE=https://api-staging.example.comCONFIG_URL=https://config.example.com/mobile.jsonDart में, इन्हें String.fromEnvironment से पढ़ें और स्टार्टअप पर एक सरल AppConfig ऑब्जेक्ट बनाएं।
अगर आप छोटे endpoint बदलावों के लिए रीबिल्ड से बचना चाहते हैं, तो API बेस URL को एक कॉन्स्टैंट न समझें। ऐप लॉन्च पर एक छोटी config फ़ाइल फेच करें (और कैश करें)। फ्लेवर केवल यह तय करता है कि config कहाँ से फेच करनी है।
व्यावहारिक विभाजन:
अगर आप अपना बैकएंड मूव करते हैं, तो आप remote config अपडेट कर के बेस URL बदल सकते हैं। मौजूदा यूज़र्स अगले लॉन्च पर इसे पिक कर लेंगे, और पिछली कैश्ड वैल्यू सुरक्षित fallback रहेगी।
फ़ीचर फ्लैग्स ग्रैडुअल रोलआउट, A/B टेस्ट, क्विक किल स्विच और स्टेजिंग में रिस्की बदलाव टेस्ट करने के लिए उपयोगी हैं। वे सुरक्षा नियंत्रण का विकल्प नहीं हैं। अगर कोई फ्लैग किसी एसेट को गार्ज़ करता है जिसे सुरक्षा की जरूरत है, तो वह फ्लैग नहीं — वह auth नियम है।
हर फ्लैग को एक API की तरह ट्रीट करें: स्पष्ट नाम, एक owner, और एक end date।
ऐसे नाम रखें जो बताएं कि जब फ्लैग ON है तो क्या होता है, और प्रोडक्ट के किस हिस्से को छूता है। एक आसान स्कीम:
feature.checkout_new_ui_enabled (कस्टमर-फेसिंग फीचर)ops.payments_kill_switch (आपातकालीन ऑफ़ स्विच)exp.search_rerank_v2 (एक प्रयोग)release.api_v3_rollout_pct (ग्रैजुअल रोलआउट)debug.show_network_logs (डायग्नोस्टिक्स)सकारात्मक बूलियन (..._enabled) को प्राथमिकता दें ताकि डबल निगेटिव से बचा जा सके। स्थिर प्रीफिक्स रखें ताकि आप फ्लैग्स खोज और ऑडिट कर सकें।
सेफ डिफ़ॉल्ट से शुरू करें: अगर फ्लैग सेवा डाउन है, आपका ऐप स्थिर वर्ज़न जैसा व्यवहार करना चाहिए।
एक यथार्थवादी पैटर्न: बैकएंड में नया endpoint शिप करें, पुराना बनाए रखें, और release.api_v3_rollout_pct से धीरे-धीरे ट्रैफ़िक मूव करें। अगर एरर बढ़े तो उसे बिना हॉटफिक्स के वापस फ्लिप करें।
फ्लैग्स के ढेर को रोकने के लिए कुछ नियम रखें:
“सीक्रेट” कुछ भी है जिसका लीक होना नुकसानदायक हो। सोचें: API टोकन, डेटाबेस पासवर्ड, OAuth क्लाइंट सीक्रेट्स, साइनिंग कीज़ (JWT), webhook सीक्रेट्स और प्राइवेट सर्टिफ़िकेट। सीक्रेट नहीं हैं: API बेस URL, बिल्ड नंबर, फीचर फ्लैग्स, या पब्लिक एनालिटिक्स IDs।
सीक्रेट्स को बाकी सेटिंग्स से अलग रखें। डेवलपर्स को सुरक्षित कॉन्फ़िग आसानी से बदलने दे पर सीक्रेट्स केवल रनटाइम पर और केवल जहाँ ज़रूरी हों वहां इंजेक्ट हों।
Dev में, सीक्रेट लोकल और डिस्पोज़ेबल रखें। .env फाइल या OS keychain का उपयोग करें और इसे रीसेट करना आसान बनाएं। कभी कमिट न करें।
Staging और prod में, सीक्रेट्स को समर्पित सीक्रेट स्टोर में रखें, न कि कोड रेपो में, चैट लॉग में, या मोबाइल ऐप में बेक किए हुए।
रोटेशन फेल होता है जब आप एक की बदलते हैं और पुराने क्लाइंट्स अभी भी उसका उपयोग करते हैं। ओवरलैप विंडो की योजना बनाएं।
यह ओवरलैप अप्रोच API कीज़, webhook सीक्रेट्स और साइनिंग कीज़ के लिए काम करता है और अचानक आउटेज से बचाता है।
आपके पास एक staging API और नया production API है। लक्ष्य ट्रैफ़िक को चरणबद्ध तरीके से मूव करना है, और कुछ गड़बड़ लगे तो जल्दी वापस आ सकें। यह तब सरल होता है जब ऐप API बेस URL को कोड में न रखकर कॉन्फ़िग से पढ़े।
हर जगह API URL को deploy-time वैल्यू माने। वेब ऐप (React) में यह अक्सर बिल्ड-टाइम वैल्यू या रनटाइम config फ़ाइल होता है। मोबाइल (Flutter) में यह आमतौर पर एक फ्लेवर प्लस remote config होता है। बैकएंड (Go) में यह रनटाइम env var होता है। महत्वपूर्ण बात यह है कि कोड एक ही वैरिएबल नाम (उदाहरण के लिए, API_BASE_URL) उपयोग करे और कम्पोनेंट्स, सर्विसेज़ या स्क्रीन में URL एम्बेड न करें।
एक सुरक्षित चरणबद्ध रोलआउट इस तरह दिख सकता है:
वेरिफिकेशन का अधिकतर काम मिसमैच पकड़ना है। असली यूज़र्स परिवर्तन से पहले, health endpoints, auth फ्लो और एक टेस्ट अकाउंट से एक प्रमुख जर्नी end-to-end पूरा होने की पुष्टि करें।
अधिकांश प्रोडक्शन कॉन्फ़िग बग बोरिंग होते हैं: एक स्टेजिंग मान रह गया, एक फ्लैग डिफ़ॉल्ट उल्टा था, या किसी क्षेत्र में API की गायब थी। एक तेज पास अधिकांशको पकड़ लेता है।
डिप्लॉय करने से पहले, पुष्टि करें कि तीन चीज़ें लक्ष्य वातावरण से मेल खाती हैं: endpoints, सीक्रेट्स और डिफ़ॉल्ट्स।
फिर एक फास्ट स्मोक टेस्ट करें। एक वास्तविक यूज़र फ्लो चुनें और उसे end to end चलाएँ, एक ताजा इंस्टॉल या क्लीन ब्राउज़र प्रोफ़ाइल का उपयोग करें ताकि आप कैश्ड टोकन पर निर्भर न रहें।
एक व्यावहारिक आदत: staging को production की तरह ट्रीट करें बस अलग मानों के साथ। इसका मतलब वही कॉन्फ़िग स्कीमा, वही वेलिडेशन नियम और वही डिप्लॉयमेंट आकार होना चाहिए। संरचना को परिवर्तित न करें; केवल मान बदलें।
ज़्यादातर कॉन्फ़िग आउटेज जटिल नहीं होते। वे साधारण गलतियाँ हैं जो फाइलों, बिल्ड स्टेप्स और डैशबोर्ड्स में फैली कॉन्फ़िग के कारण छूट जाती हैं, और कोई उत्तर नहीं दे पाता: "यह ऐप अभी कौन-से मान उपयोग करेगा?" एक अच्छा सेटअप उस सवाल का उत्तर आसान बना देता है।
एक आम जाल runtime मानों को build-time जगहों में डालना है। React बिल्ड में API बेस URL बेक करना मतलब हर वातावरण के लिए फिर से बिल्ड करना। फिर कोई गलत आर्टिफैक्ट डिप्लॉय कर देता है और प्रोडक्शन स्टेजिंग को प्वाइंट कर देता है।
एक सुरक्षित नियम: केवल उन्हीं मानों को बिल्ड में बेक करें जो रिलीज़ के बाद सचमुच कभी नहीं बदलते (जैसे ऐप वर्ज़न)। जहां संभव हो, environment विवरण (API URLs, फीचर स्विच, analytics endpoints) को runtime रखें, और सोर्स ऑफ ट्रुथ स्पष्ट रखें।
यह तब होता है जब डिफ़ॉल्ट्स "हेल्पफुल" लेकिन असुरक्षित होते हैं। एक मोबाइल ऐप अगर कॉन्फ़िग पढ़ न सके तो dev API पर डिफ़ॉल्ट कर सकता है, या बैकएंड env var गायब होने पर लोकल डेटाबेस पर fallback कर सकता है। यह एक छोटी सी कॉन्फ़िग गलती को पूरे आउटेज में बदल देता है।
दो आदतें मदद करती हैं:
एक यथार्थ उदाहरण: एक रिलीज़ शुक्रवार रात को जाती है, और प्रोडक्शन बिल्ड में गलती से एक स्टेजिंग भुगतान की मौजूद है। सब "काम" करता है जब तक चार्जेज चुपचाप फेल न हों। सुधार नया पेमेंट लाइब्रेरी नहीं है। यह वेलिडेशन है जो प्रोडक्शन में गैर-प्रोड कीज़ को रिजेक्ट कर दे।
अगर स्टेजिंग प्रोडक्शन से मेल नहीं खाती तो यह गलत आत्मविश्वास देती है। अलग डेटाबेस सेटिंग्स, गायब बैकग्राउंड जॉब्स, या अतिरिक्त फीचर फ्लैग्स बग्स को केवल लॉन्च के बाद ही दिखने देंगे।
स्टेजिंग को करीबी रखें: वही कॉन्फ़िग स्कीमा, वही वेलिडेशन नियम और वही डिप्लॉयमेंट आकार मिरर करें। केवल मान अलग होने चाहिए, संरचना नहीं।
लक्ष्य फैंसी टूलिंग नहीं है। लक्ष्य बोरिंग स्थिरता है: वही नाम, वही प्रकार, वही नियम dev, staging और prod में। जब कॉन्फ़िग अनुमान्य हो जाती है, रिलीज़ रिस्की महसूस करना बंद कर देती हैं।
एक जगह एक साफ़ कॉन्फ़िग कॉन्ट्रैक्ट लिख कर शुरू करें। इसे छोटा पर विशिष्ट रखें: हर की का नाम, उसका प्रकार (string, number, boolean), कहाँ से आ सकता है (env var, remote config, build-time), और उसका डिफ़ॉल्ट। ऐसे मानों के लिए नोट्स जोड़ें जिन्हें क्लाइंट ऐप में कभी नहीं सेट किया जाना चाहिए (जैसे प्राइवेट API कीज़)। इस कॉन्ट्रैक्ट को एक API की तरह ट्रीट करें: बदलावों को रिव्यू की ज़रूरत होनी चाहिए।
फिर गलतियों को जल्दी फेल कराएं। missing API base URL का सबसे अच्छा समय CI में पकड़ना है, डिप्लॉय के बाद नहीं। वही तरह की automated validation जोड़ें जो आपकी ऐप जैसी ही तरीके से कॉन्फ़िग लोड करे और चेक करे:
अंत में, जब कॉन्फ़िग बदलाव गलत निकलें तो उसे जल्दी रिकवर करना आसान बनाएं। जो चल रहा है उसका स्नैपशॉट लें, एक समय में एक ही चीज़ बदलें, जल्दी वेरिफाई करें, और एक रोलबैक पाथ रखें।
अगर आप Koder.ai (koder.ai) जैसे प्लेटफ़ॉर्म के साथ बिल्ड और डिप्लॉय कर रहे हैं, तो वही नियम लागू होते हैं: एनवायरनमेंट मानों को बिल्ड और होस्टिंग के इनपुट मानें, सीक्रेट्स को एक्सपोर्टेड सोर्स में न डालें, और शिप करने से पहले कॉन्फ़िग वेलिडेट करें। यही स्थिरता redeploys और रोलबैक को नियमित महसूस कराती है।
जब कॉन्फ़िग डाक्यूमेंटेड, वेलिडेटेड और रिवर्सिबल हो जाती है, तो यह आउटेज का स्रोत बनना बंद कर देती है और शिपिंग का एक सामान्य हिस्सा बन जाती है।