Every setting of the file becomes a secret, under the name the file gives it.
- Dashboard: open an environment, choose Import, then drop the file, browse to it, or paste its text. You see every key before anything is saved, and you can untick the ones that aren't secrets.
- CLI:
productenv push --file appsettings.jsonuploads a file andproductenv diff --file …compares it. The format comes from the file name, or from--format. See the CLI guide. - Names are never changed:
ConnectionStrings:Defaultandspring.datasource.urlare stored exactly like that, and every line is imported, empty values included. - Where only environment variable names work (a
.envdownload,productenv run, GitHub, deploy providers), ProductEnv sendsConnectionStrings__Default. Pushing that.envback updates the same keys. - A name a key can't hold (a space,
$) is listed as not imported, with the reason.
One KEY=value per line. export prefixes, quotes and # comments are fine; a value on several lines goes in double quotes.
.env.env.productionprod.envsecrets.txt# Comments and blank lines are skipped
DATABASE_URL=postgres://app:change-me@db:5432/shop
export STRIPE_KEY=sk_test_example
GREETING="Hello, world"| Key | Value |
|---|---|
DATABASE_URL | postgres://app:change-me@db:5432/shop |
STRIPE_KEY | sk_test_example |
GREETING | Hello, world |
- A
KEY=line is imported with an empty value. - Templates such as
.env.exampleorappsettings.sample.jsonhold placeholders, so the dashboard does not import them.
An object of keys, like the file Flutter's --dart-define-from-file reads. A nested setting joins its names with . (Features.Beta); numbers and booleans are kept as text.
config.jsonany other *.json{
"API_URL": "https://api.example.com",
"STRIPE_KEY": "sk_test_example",
"Features": { "Beta": true }
}| Key | Value |
|---|---|
API_URL | https://api.example.com |
STRIPE_KEY | sk_test_example |
Features.Beta | true |
nulland empty values are imported as empty values.
Every setting keeps its .NET name: ConnectionStrings:Default, Logging:LogLevel:Microsoft.AspNetCore. Comments and trailing commas are fine.
appsettings.jsonappsettings.Development.json{
// Comments and trailing commas are fine
"ConnectionStrings": {
"Default": "Server=db;Database=shop;Password=change-me"
},
"Stripe": { "ApiKey": "sk_test_example" },
"AllowedHosts": "*",
}| Key | Value |
|---|---|
ConnectionStrings:Default | Server=db;Database=shop;Password=change-me |
Stripe:ApiKey | sk_test_example |
AllowedHosts | * |
- Untick the settings that are not secrets (
Logging,AllowedHosts…) before you import. - List items use their index:
Hosts:0,Hosts:1. - Where only environment variable names work (a
.envdownload, GitHub, Vercel…), it is sent asConnectionStrings__Default, the name .NET reads from them.
The file dotnet user-secrets keeps: every name is imported as written, Stripe:ApiKey included.
secrets.json{
"ConnectionStrings:Default": "Server=db;Database=shop;Password=change-me",
"Stripe:ApiKey": "sk_test_example"
}| Key | Value |
|---|---|
ConnectionStrings:Default | Server=db;Database=shop;Password=change-me |
Stripe:ApiKey | sk_test_example |
Reads <appSettings> and <connectionStrings>, names as written; each connection string becomes ConnectionStrings:<name>, as .NET reads it. Everything else in the file is left alone.
web.configapp.configsecrets.configconnectionStrings.config<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="StripeApiKey" value="sk_test_example" />
</appSettings>
<connectionStrings>
<add name="Default" connectionString="Server=db;Database=shop;Password=change-me" />
</connectionStrings>
</configuration>| Key | Value |
|---|---|
StripeApiKey | sk_test_example |
ConnectionStrings:Default | Server=db;Database=shop;Password=change-me |
- Downloads never rewrite your
web.config: you getsecrets.configandconnectionStrings.configto point it to.
Every line is imported under its name as written: spring.datasource.url, spring.jpa.open-in-view.
application.propertieslocal.propertiesgradle.properties# Spring
spring.datasource.url=jdbc:postgresql://db:5432/shop
spring.datasource.password=change-me
MAPS_API_KEY=AIzaExample| Key | Value |
|---|---|
spring.datasource.url | jdbc:postgresql://db:5432/shop |
spring.datasource.password | change-me |
MAPS_API_KEY | AIzaExample |
- A
KEY=line is imported with an empty value.
A nested setting joins its names with ., the way Spring names it: spring.datasource.url; list items use their index (hosts.0).
application.ymlapplication-dev.yamlany other *.ymlspring:
datasource:
url: jdbc:postgresql://db:5432/shop
password: change-me
stripe:
apiKey: sk_test_example| Key | Value |
|---|---|
spring.datasource.url | jdbc:postgresql://db:5432/shop |
spring.datasource.password | change-me |
stripe.apiKey | sk_test_example |
- A setting without a value (
key:or~) is imported with an empty value.
Every getter and constant is imported under its own name: shopApi stays shopApi, and an env.dart download keeps it.
app_config.dartapp_config_prod.dartany *.dart config classimport 'package:shop/config/app_config.dart';
class AppConfigStaging extends AppConfig {
@override
Env get environment => Env.staging;
@override
String get shopApi => 'https://staging-api.example.com';
@override
String get basicAuthToken =>
'dXNlcjpjaGFuZ2UtbWU=';
@override
bool get enableExperimentalFeatures => true;
@override
String get appId => switch (Platform.operatingSystem) {
'android' => 'com.example.shop',
_ => '1234567890',
};
static const mapsKey = 'AIzaExample';
}| Key | Value |
|---|---|
environment | Env.staging |
shopApi | https://staging-api.example.com |
basicAuthToken | dXNlcjpjaGFuZ2UtbWU= |
enableExperimentalFeatures | true |
appId | switch (Platform.operatingSystem) { 'android' => 'com.example.shop', _ => '1234567890', } |
mapsKey | AIzaExample |
- A value worked out in code (a
switch, aPlatformcheck, an enum such asEnv.staging,null) is imported exactly as written, and the import lists it so you can check it. String.fromEnvironment('API_URL', defaultValue: '…')imports asAPI_URLwith its default.- One class per environment: when a file has several classes setting the same keys, the first is read. Import each from a file of its own.
- A downloaded
env.dartholds key names only, so it has nothing to import. - Anything built into a mobile app can be read back out of it. Keep server secrets on your backend and pass the rest at build time with
flutter run --dart-define-from-file.
If your file's format isn't on this page, or a file doesn't import the way it should, report it and we'll look into it.
Formats we don't read yet include .xcconfig (Xcode), .tfvars (Terraform), TOML and INI. Until then, paste the values into a .env file and import that.
Bug reports are public