ТакПростоТакПросто.ai
ЦеныДля бизнесаОбразованиеДля инвесторов
ВойтиНачать

Продукт

ЦеныДля бизнесаДля инвесторов

Ресурсы

Связаться с намиПоддержкаОбразованиеБлог

Правовая информация

Политика конфиденциальностиУсловия использованияБезопасностьПолитика допустимого использованияСообщить о нарушении
ТакПросто.ai

© 2026 ТакПросто.ai. Все права защищены.

Главная›Блог›Схема конфигурации dev staging prod без хардкода URL и ключей
24 авг. 2025 г.·6 мин

Схема конфигурации dev staging prod без хардкода URL и ключей

Практичная схема конфигурации dev staging prod для веб, бэкенда и мобильного приложения: где хранить URL, ключи и фичи, чтобы не хардкодить.

Схема конфигурации dev staging prod без хардкода URL и ключей

Зачем разделять dev, staging и prod

development (dev), staging и production (prod) - это одно и то же приложение в разных условиях. Код часто совпадает почти полностью, но настройки обязаны отличаться. Иначе вы проверяете одно, а пользователям уезжает другое.

Dev нужен для быстрой разработки: частые перезапуски, тестовые данные, подробные логи. Staging - репетиция продакшена: максимально похоже на prod, но безопасно, чтобы прогонять релизы, миграции и интеграции. Prod - среда для реальных пользователей, поэтому там минимум лишнего и максимум контроля.

Обычно различаются: адреса внешних сервисов и API, ключи и токены (платежи, push, SMTP), feature flags, аналитика, уровень логирования и отладочные экраны.

Хардкод ломает все сразу. Один случайный коммит с боевым ключом в мобильное приложение - и его уже не отозвать у пользователей. Один забытый URL в вебе - и staging начинает писать данные в продовую базу. Еще хуже, когда фича включена прямо в коде: тесты проходят, а релиз внезапно ведет себя иначе.

Хорошая схема конфигурации делает поведение предсказуемым: вы меняете окружение, и меняются только настройки, а не логика. Она должна быть повторяемой (сборки одинаковые), понятной команде и безопасной по умолчанию.

Практический ориентир простой: разработчик запускает dev локально, QA проверяет staging, а релизный пайплайн собирает prod без ручных правок. Если вы собираете проект в TakProsto (takprosto.ai), удобно держать значения по окружениям через переменные окружения и заранее планировать, какие параметры где задаются, чтобы не хранить важное в исходниках.

Базовые принципы: что где хранить

Цель одна: ни один URL, ключ или переключатель не должен быть захардкожен в коде. Тогда смена окружения - это подстановка настроек, а не правка файлов и нервные релизы.

Первое правило - отделяйте публичные настройки от секретов. Все, что попадает в клиент (браузер или мобильное приложение), считайте публичным: это можно извлечь из сборки и прочитать.

На клиенте допустимы: API_BASE_URL, имя окружения (APP_ENV), включенность фичи (FEATURE_NEW_UI), публичный ключ аналитики.

На клиенте недопустимы: токены доступа, приватные ключи, пароли к БД, ключи платежей и любые сервисные секреты.

Второе правило - выбирайте источник конфигурации по типу данных. Простые параметры удобно задавать через переменные окружения или локальные конфиг-файлы. Секреты должны приходить из секрет-хранилища или защищенных переменных CI/CD. Переключатели, которые вы хотите менять без релиза, живут в удаленной конфигурации, но она все равно не должна раздавать секреты.

Третье правило - одинаковые имена везде. Если у вас есть API_BASE_URL и SENTRY_DSN, держите эти названия одинаковыми в web, backend и mobile. Это резко снижает путаницу.

Четвертое правило - различайте настройки сборки и запуска. Сборка - то, что запекается в клиент (например, базовый URL для web/mobile). Запуск - то, что читает сервер при старте (например, DATABASE_URL, JWT_SECRET). Если значение должно меняться без пересборки клиента, оно не должно быть частью build-конфига.

Единая схема конфигурации для всех частей продукта

У web, backend и mobile должен быть один и тот же набор настроек и одни и те же названия. Тогда схема не превращается в набор исключений.

Начните со словаря ключей и держите его единым для всех платформ. Не так важно, где лежат значения (env, файлы, секрет-хранилище). Важны названия и смысл. Хорошее правило: дефолты допустимы для разработки, но в продакшене все критичное должно быть задано явно, а сборка или запуск должны падать, если чего-то не хватает.

Чтобы не смешивать все в одну кучу, группируйте параметры по доменам: network (URL, таймауты), auth (issuer, redirect), features (флаги), logging (уровни, сбор ошибок), payments (провайдер, тестовый режим).

Документировать конфиг удобно одной таблицей и короткими примерами:

КлючДоменПример (dev)Пример (prod)Обязателен в prod
APP_ENVcoredevprodда
API_BASE_URLnetworkhttp://localhost:8080https://api.example.ruда
FEATURE_NEW_CHECKOUTfeaturestruefalseнет
LOG_LEVELloggingdebugwarnда

Практика, которая спасает нервы: один и тот же ключ должен значить одно и то же везде. Если в Go это API_BASE_URL, то и в React, и во Flutter он называется так же, а не BASE_URL и server.

Веб (React): практичный способ подключать настройки

В React важно помнить: большинство переменных окружения попадает в бандл на этапе сборки. Если вы хотите поменять API_BASE_URL после сборки, обычно ничего не выйдет, пока вы не пересоберете фронтенд.

Рабочая схема: читайте настройки из одного места, например из config.ts. Так по коду не расползаются магические строки, и URL не приходится править руками.

// src/config.ts
const env = (import.meta as any).env || (process as any).env;

export const config = {
  envName: env.VITE_ENV_NAME || env.REACT_APP_ENV_NAME || "dev",
  apiBaseUrl: env.VITE_API_BASE_URL || env.REACT_APP_API_BASE_URL || "http://localhost:8080",
  enableNewCheckout: (env.VITE_FEATURE_NEW_CHECKOUT || env.REACT_APP_FEATURE_NEW_CHECKOUT) === "true",
};

Для окружений заведите отдельные файлы, которые подхватывает сборка или CI. Типовой набор: .env.development, .env.staging, .env.production, плюс переменные в CI (чтобы не хранить значения в репозитории).

Чтобы быстрее ловить ошибки, сделайте небольшую debug-страницу, которая показывает только безопасные настройки: имя окружения, базовый URL API, включенные фичи. Никогда не выводите токены, секреты и ключи.

Отдельная ловушка - кэш и пересборка. При service worker или агрессивном кешировании браузер может продолжать отдавать старый бандл со старыми переменными. Симптом простой: API_BASE_URL поменяли, а запросы все равно идут на прежний адрес. Обычно помогает пересборка, новая версия ассетов и корректная инвалидизация кэша.

Бэкенд (Go): конфигурация при запуске и безопасные секреты

Для Go-сервиса надежный подход простой: вся конфигурация читается один раз при старте, затем сервис работает с уже собранным Config. Так вы не держите URL, ключи и пароли в коде, а поведение в каждом окружении предсказуемо.

Для локальной разработки удобно иметь файл (например, .env.local или config.local.yaml), который подхватывается только на вашей машине. В staging и prod лучше опираться на переменные окружения, которые задаются в системе деплоя. В репозиторий файл не коммитьте, максимум шаблон.

Секреты (пароль БД, токены, ключи шифрования) должны приходить только из секрет-хранилища или ENV. Даже если несекретные настройки лежат в файле, секреты держите отдельно.

Нужна жесткая валидация: если нет обязательных значений, сервис не должен стартовать. Это дешевле, чем ловить ошибки в рантайме.

package config

import (
  "log"
  "os"
)

type Config struct {
  Env         string
  HTTPPort    string
  DatabaseURL string
  JWTSecret   string
  FeatureX    bool
}

func mustGet(key string) string {
  v := os.Getenv(key)
  if v == "" {
    log.Fatalf("missing required env: %s", key)
  }
  return v
}

func Load() Config {
  cfg := Config{
    Env:         mustGet("APP_ENV"),
    HTTPPort:    mustGet("HTTP_PORT"),
    DatabaseURL: mustGet("DATABASE_URL"),
    JWTSecret:   mustGet("JWT_SECRET"),
  }

  log.Printf("config: env=%s port=%s db=%s", cfg.Env, cfg.HTTPPort, "[set]")
  return cfg
}

В логах печатайте только безопасные поля. Для секретов используйте маску вроде [set] или выводите длину значения. Так вы упрощаете дебаг и не роняете токены в логи.

Мобильное приложение (Flutter): окружения без хаоса

Настройте окружения без хардкода
Соберите web, backend и mobile в TakProsto и задайте dev, staging и prod через переменные окружения.
Попробовать

В мобильном клиенте хаос начинается, когда один и тот же билд пытаются подкрутить под разные окружения вручную. Надежнее сделать разные сборки: dev, staging и prod. Тогда всегда понятно, куда идет трафик, какие фичи включены и почему у тестировщика вдруг не работает оплата.

Разделите сборки через flavors и отдельные entrypoints

Практичная схема: на Android завести productFlavors (dev/staging/prod), на iOS - Schemes (Dev/Staging/Prod), а в Flutter - три входных файла main_dev.dart, main_staging.dart, main_prod.dart.

В каждом main_*.dart передавайте только публичные настройки и идентификатор окружения, например через --dart-define (удобно для CI) или через фабрику конфигурации.

Обычно в конфиг клиента кладут: envName, apiBaseUrl, публичные идентификаторы аналитики (если они не секрет), дефолтные feature flags.

Секреты: не в репозиторий и не в клиент

Если ключ дает доступ к данным или деньгам, его не должно быть в приложении вообще. Мобильное приложение легко декомпилировать, и скрытый ключ быстро станет публичным. Правильный путь: хранить секреты на бэкенде, а клиенту отдавать только короткоживущие токены или уже готовый результат (например, подпись, платежную сессию, прокси-запрос).

Переключатель окружения для тестировщиков (без секретов)

Тестировщикам часто нужно быстро переключиться между dev и staging. Делайте это только в dev/staging сборках: скрытый экран по долгому нажатию на версию в настройках. На экране - выбор из заранее зашитого списка apiBaseUrl (без ввода произвольного URL) и кнопка «Перезапустить с новым окружением». Выбор храните в SharedPreferences.

Фичи и переключатели: как управлять feature flags

Feature flags (фиче-флаги) - переключатели, которые меняют поведение приложения без нового релиза. Они помогают выкатывать изменения по шагам, включать фичу части пользователей и быстро выключать проблемную часть, если что-то пошло не так.

Флаги хорошо ложатся на разделение окружений, если заранее договориться, где они живут и кто ими управляет.

Где хранить флаги

На практике обычно комбинируют несколько источников: локально в dev (env или файл) для экспериментов, а на staging и prod - через бэкенд. Например, бэкенд отдает /config, а сами флаги лежат в БД и кешируются.

Правила безопасности и качества

Флаг не должен решать вопросы безопасности. Он может скрыть кнопку или поменять сценарий, но не должен открывать доступ к данным. Права и проверки всегда на бэкенде.

Чтобы флаги не превратились в мусор, договоритесь о дисциплине: понятное имя (например, new_checkout_ui), значение по умолчанию, владелец, срок удаления, и минимальное логирование, чтобы было видно, когда флаг включен.

Пример: добавили новый экран оплаты. В dev флаг включен всегда. На staging включаете для тестировщиков. На prod включаете для 5% пользователей, смотрите ошибки и метрики, затем расширяете. Если пошли сбои, выключаете флаг, и продукт продолжает работать без срочного релиза.

Секреты и ключи: хранение, доступ, ротация

Откатывайтесь без паники
Снимки и откат помогают безопасно проверять релизы и быстро возвращаться к рабочей версии.
Сделать снимок

Секреты - это не просто строчки в .env. Это данные, утечка которых дает доступ к деньгам, аккаунтам или базе. В нормальной схеме секреты всегда отделены от обычных настроек и никогда не попадают в репозиторий.

Типовые секреты: JWT_SECRET или ключи подписи, доступ к базе (пароль, DSN), ключи платежных систем, OAuth client secret, API keys для почты, SMS, пушей, аналитики.

Дальше важнее не «где хранить», а кто имеет доступ. Разделяйте права: разработчику обычно достаточно dev, тестировщикам - staging, а prod должен быть доступен только тем, кто релизит и поддерживает. В CI держите секреты в защищенном хранилище переменных и выдавайте только нужным джобам, чтобы случайный вывод окружения не раскрыл ключи.

Ротация ключей должна проходить без простоя и без ломания клиентов. Рабочая схема - поддерживать два ключа одновременно на период перехода:

  • добавьте новый ключ параллельно старому
  • начните подписывать новые токены новым ключом
  • принимайте токены, подписанные обоими ключами
  • дождитесь окончания TTL старых токенов
  • удалите старый ключ и зафиксируйте дату ротации

Самая частая ошибка - секреты в логах, ошибках и аналитике. Не логируйте заголовки Authorization, параметры запросов с токенами и полные конфиги.

Пример из жизни: одна фича, три окружения

Разработчик добавляет интеграцию, например отправку событий во внешний сервис аналитики. Чтобы быстрее проверить, он временно прописывает тестовый URL прямо в коде. Локально все работает, задача закрыта.

Проблема всплывает на staging. Тестировщик включает фичу и видит странность: события уходят, но не появляются в тестовом кабинете, а часть запросов падает. В логах бэкенда видно, что приложение ходит на test-api.example, хотя на staging должен быть staging-api.

Поиск идет по цепочке: сетевые логи фронта, конфиг бэкенда, затем grep по репозиторию. И часто источник один: хардкод в React, дефолт в Go-конфиге или константа во Flutter.

Когда конфигурация разнесена по окружениям, фикса занимает минуты. Добавляете явный параметр, например ANALYTICS_BASE_URL, задаете значения для каждого окружения и ловите ошибку на старте, если переменной нет.

Рабочий порядок действий:

  • добавьте параметр в единый список настроек (с описанием и примером)
  • задайте значения для dev, staging и prod (в env-файлах или в секретах CI/CD)
  • включите валидацию: если переменная не задана или в prod похожа на тестовую, сборка падает
  • прогоните staging-сценарий и проверьте, что логи печатают только безопасные поля

Закрепите это в код-ревью: любые URL, ключи и переключатели берутся только из конфигурации, а не из констант.

Частые ошибки и ловушки

Самый частый источник странных багов между dev, staging и prod - когда путают настройки сборки и настройки запуска. Например, фронт собрали с одним API URL, а потом пытаются перекинуть его на другой через переменные окружения на сервере. В итоге часть значений уже вшита в бандл, а часть читается при старте, и в проде получается каша.

Вторая ловушка - забыть выключить dev-инструменты. Подробные логи, отладочные экраны, тестовые меню и «показать ошибку целиком» полезны в разработке, но в prod они мешают и иногда раскрывают детали системы.

Отдельная боль - мобильные сборки. Если зашить URL или тестовые ключи прямо в код, они уедут к пользователям навсегда. Типовой сценарий: Flutter-приложение случайно указывает на staging, а пользователи видят пустую базу и думают, что сервис сломан.

Частые ошибки:

  • один и тот же секрет используется в dev, staging и prod
  • в коде остаются захардкоженные URL или токены «временно»
  • логирование и дебаг включены в prod по умолчанию
  • конфиг меняют вручную в одном сервисе и забывают в другом
  • после отката (rollback) не возвращают конфигурацию к версии релиза

Практический пример: вы включили новую оплату только на staging через feature flag, а в prod забыли. Потом делаете rollback, но флаг остается включенным, и старый код падает на неизвестной настройке. Выход простой: версионируйте конфиги вместе с релизом и храните секреты раздельно по окружениям.

Быстрый чеклист перед сборкой и релизом

Деплой без ручных правок
Разверните приложение с хостингом и деплоем, не меняя код ради разных окружений.
Развернуть

Перед релизом полезно сделать короткую проверку: у каждого окружения должны быть свои значения, секреты не должны утечь, а ошибки конфига должны ловиться до деплоя.

1) Проверка значений по окружениям

Убедитесь, что для dev, staging и prod заданы разные значения всех обязательных параметров: base URL для API, адреса веба и бэка, аналитика, пуши, хранилища, домены, фича-флаги по умолчанию. Частая проблема: staging случайно указывает на prod базу.

2) Секреты и видимость

Проверьте, что секреты и ключи API не попадают в репозиторий и не оказываются в клиенте (web и mobile). Любая сборка, которую можно скачать, считается публичной.

3) Валидация и логи

Перед стартом приложения должна быть валидация конфига: если не хватает переменной окружения или формат неверный, сервис не запускается. В логах выводите только безопасное: имя окружения, включенные фичи, адреса сервисов, но не секреты.

4) Флаги и контроль изменений

Для фиче-флагов держите минимум дисциплины: владелец, цель, значения для dev/staging/prod, срок жизни, план отката, способ ручной проверки.

Следующие шаги: как это собрать в TakProsto

Чтобы конфигурация не расползалась по чатам, файлам и временным правкам, выберите одно понятное правило: где живут значения и как они попадают в web, backend и mobile при сборке и запуске.

В TakProsto обычно удобно держать окружения как отдельные сборки или отдельные проекты (зависит от доменов, баз и доступов). Смысл один: то же приложение, но разные значения параметров и секретов для dev, staging и prod.

Planning mode помогает не забыть важное: выпишите список параметров и места, где они используются (base URL для API, ключи сторонних сервисов, флаги, имя окружения, настройки логов). Это снижает шанс, что кто-то «на минутку» вставит URL прямо в код.

Практичный порядок действий:

  • составьте словарь параметров: имя, тип (строка, bool), где используется (React, Go, Flutter), кто меняет
  • создайте dev, staging и prod и задайте значения для каждого окружения отдельно
  • секреты храните отдельно от обычных настроек и выдавайте доступ только тем, кому нужно
  • делайте релиз вместе с версией конфигурации: перед изменениями создавайте снимок, чтобы можно было быстро откатиться
  • если планируете экспорт исходников, проверьте, что параметры остаются параметрами и не превращаются в захардкоженные строки

Пример: вы включаете новую оплату. В dev фича включена и ходит на тестовый провайдер, в staging включена только для команды, в prod включена для всех. Меняются лишь значения конфигурации, а не код. Это и есть цель: один код, три окружения, ноль хардкода. "}

FAQ

Зачем вообще нужны dev, staging и prod, если код почти одинаковый?

Разделяйте конфигурацию по окружениям: код один, а значения разные.

Минимум:

  • dev — быстрые правки, тестовые данные, подробные логи
  • staging — максимально похоже на prod, но безопасно для проверок релиза
  • prod — реальные пользователи, минимум лишнего, строгий контроль
Чем staging должен отличаться от prod на практике?

Staging должен быть «репетицией» prod:

  • те же версии сервисов и зависимости
  • похожая инфраструктура (БД, кеш, очереди), но отдельные ресурсы
  • те же миграции и пайплайн релиза

Главное правило: staging никогда не должен писать в prod-базу и использовать боевые ключи.

Как не допустить хардкода URL и ключей в коде?

Железное правило: не хардкодить.

Вместо этого:

  • значения (URL, флаги) — через переменные окружения/конфиги
  • секреты — только через защищенные переменные CI/CD или секрет-хранилище
  • в коде — один модуль config, который читает всё из окружения

Если параметр обязателен — падайте на старте/сборке, а не «как-нибудь потом».

Какие настройки можно хранить в клиенте (web/mobile), а какие нельзя?

Считайте публичным всё, что попадает в сборку web/mobile.

Можно в клиенте:

  • API_BASE_URL, APP_ENV
  • FEATURE_* флаги
  • публичные идентификаторы аналитики (если они не дают доступа)

Нельзя в клиенте:

  • пароли, приватные ключи, DATABASE_URL
  • ключи платежей, OAuth client secret
  • любые токены, которые открывают доступ к данным или деньгам
Что такое конфигурация сборки и конфигурация запуска — и почему это важно?

Build-time — запекается в сборку и не меняется без пересборки клиента.

Run-time — читается при запуске сервера и может меняться без пересборки.

Практика:

  • Web/Mobile: API_BASE_URL часто build-time
  • Backend: DATABASE_URL, JWT_SECRET всегда run-time

Если хотите менять значение «без релиза клиента», не делайте его частью build-конфига.

Как сделать единую схему конфигурации для web, backend и mobile?

Сделайте единый словарь ключей и используйте одинаковые имена везде.

Пример минимального набора:

  • APP_ENV
  • API_BASE_URL
  • LOG_LEVEL
  • SENTRY_DSN (если используете)
  • FEATURE_*

И закрепите смысл: один и тот же ключ означает одно и то же в React, Go и Flutter.

Как правильно подключать переменные окружения в React, чтобы не было сюрпризов?

Соберите конфиг в одном месте (например, config.ts) и не раскидывайте process.env по проекту.

Полезные практики:

  • отдельные .env.development/.env.staging/.env.production
  • маленькая debug-страница только с безопасными значениями (env, base URL, флаги)
  • учитывайте кеш: старый бандл может продолжать ходить на старый URL, пока ассеты не обновятся
Как организовать конфигурацию в Go-бэкенде безопасно и предсказуемо?

Загружайте конфиг один раз при старте и валидируйте обязательные переменные.

Практика:

  • mustGet() для обязательных параметров
  • сервис не стартует, если нет DATABASE_URL/JWT_SECRET
  • в логах выводите только безопасное: env, port, а секреты маскируйте ([set])

Это дешевле, чем ловить ошибки уже под нагрузкой.

Как не устроить хаос с окружениями в Flutter-мобильном приложении?

Делайте отдельные сборки (flavors/schemes) для dev/staging/prod.

Рекомендации:

  • разные entrypoints main_dev.dart, main_staging.dart, main_prod.dart
  • публичные значения передавайте через --dart-define
  • секретов в приложении быть не должно: всё критичное — на бэкенде

Для тестировщиков можно добавить переключение окружения только в dev/staging сборках и только из фиксированного списка URL.

Как правильно использовать feature flags, чтобы не ломать релизы и откаты?

Заведите простые правила эксплуатации:

  • флаг не должен управлять безопасностью (права и проверки только на бэкенде)
  • в prod храните значения флагов централизованно (например, отдавайте /config с бэкенда)
  • у флага должны быть: имя, дефолт, владелец, срок удаления
  • продумайте откат: выключение флага должно возвращать приложение в рабочее состояние

И не забывайте про совместимость: откат к старому коду при включенном новом флаге — частая причина падений.

Содержание
Зачем разделять dev, staging и prodБазовые принципы: что где хранитьЕдиная схема конфигурации для всех частей продуктаВеб (React): практичный способ подключать настройкиБэкенд (Go): конфигурация при запуске и безопасные секретыМобильное приложение (Flutter): окружения без хаосаФичи и переключатели: как управлять feature flagsСекреты и ключи: хранение, доступ, ротацияПример из жизни: одна фича, три окруженияЧастые ошибки и ловушкиБыстрый чеклист перед сборкой и релизомСледующие шаги: как это собрать в TakProstoFAQ
Поделиться
ТакПросто.ai
Создайте свое приложение с ТакПросто сегодня!

Лучший способ понять возможности ТакПросто — попробовать самому.

Начать бесплатноЗаказать демо