Skip to content
File formats

Every fileProductEnv imports

Drop one of these into Import in the dashboard, or push it with the CLI. Each example below shows the keys it becomes. Is your format missing, or does a file not import the way it should? Tell us.

  • .env and JSON on every plan
  • .NET, Flutter and Spring files on Team & Business
  • Dashboard, productenv push and diff

How importing works

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.json uploads a file and productenv diff --file … compares it. The format comes from the file name, or from --format. See the CLI guide.
  • Names are never changed: ConnectionStrings:Default and spring.datasource.url are stored exactly like that, and every line is imported, empty values included.
  • Where only environment variable names work (a .env download, productenv run, GitHub, deploy providers), ProductEnv sends ConnectionStrings__Default. Pushing that .env back updates the same keys.
  • A name a key can't hold (a space, $) is listed as not imported, with the reason.

.env

One KEY=value per line. export prefixes, quotes and # comments are fine; a value on several lines goes in double quotes.

Any stackEvery planFiles:.env.env.productionprod.envsecrets.txt
.env.production
# Comments and blank lines are skipped
DATABASE_URL=postgres://app:change-me@db:5432/shop
export STRIPE_KEY=sk_test_example
GREETING="Hello, world"
Keys imported from .env.production
KeyValue
DATABASE_URLpostgres://app:change-me@db:5432/shop
STRIPE_KEYsk_test_example
GREETINGHello, world
  • A KEY= line is imported with an empty value.
  • Templates such as .env.example or appsettings.sample.json hold placeholders, so the dashboard does not import them.

JSON

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.

Any stack · Flutter --dart-define-from-fileEvery planFiles:config.jsonany other *.json
config.json
{
  "API_URL": "https://api.example.com",
  "STRIPE_KEY": "sk_test_example",
  "Features": { "Beta": true }
}
Keys imported from config.json
KeyValue
API_URLhttps://api.example.com
STRIPE_KEYsk_test_example
Features.Betatrue
  • null and empty values are imported as empty values.

appsettings.json

Every setting keeps its .NET name: ConnectionStrings:Default, Logging:LogLevel:Microsoft.AspNetCore. Comments and trailing commas are fine.

.NETTeam & BusinessFiles:appsettings.jsonappsettings.Development.json
appsettings.Development.json
{
  // Comments and trailing commas are fine
  "ConnectionStrings": {
    "Default": "Server=db;Database=shop;Password=change-me"
  },
  "Stripe": { "ApiKey": "sk_test_example" },
  "AllowedHosts": "*",
}
Keys imported from appsettings.Development.json
KeyValue
ConnectionStrings:DefaultServer=db;Database=shop;Password=change-me
Stripe:ApiKeysk_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 .env download, GitHub, Vercel…), it is sent as ConnectionStrings__Default, the name .NET reads from them.

secrets.json

The file dotnet user-secrets keeps: every name is imported as written, Stripe:ApiKey included.

.NET user-secretsTeam & BusinessFiles:secrets.json
secrets.json
{
  "ConnectionStrings:Default": "Server=db;Database=shop;Password=change-me",
  "Stripe:ApiKey": "sk_test_example"
}
Keys imported from secrets.json
KeyValue
ConnectionStrings:DefaultServer=db;Database=shop;Password=change-me
Stripe:ApiKeysk_test_example

web.config

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.

.NET FrameworkTeam & BusinessFiles:web.configapp.configsecrets.configconnectionStrings.config
web.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>
Keys imported from web.config
KeyValue
StripeApiKeysk_test_example
ConnectionStrings:DefaultServer=db;Database=shop;Password=change-me
  • Downloads never rewrite your web.config: you get secrets.config and connectionStrings.config to point it to.

.properties

Every line is imported under its name as written: spring.datasource.url, spring.jpa.open-in-view.

Java · Spring · AndroidTeam & BusinessFiles:application.propertieslocal.propertiesgradle.properties
application.properties
# Spring
spring.datasource.url=jdbc:postgresql://db:5432/shop
spring.datasource.password=change-me
MAPS_API_KEY=AIzaExample
Keys imported from application.properties
KeyValue
spring.datasource.urljdbc:postgresql://db:5432/shop
spring.datasource.passwordchange-me
MAPS_API_KEYAIzaExample
  • A KEY= line is imported with an empty value.

application.yml

A nested setting joins its names with ., the way Spring names it: spring.datasource.url; list items use their index (hosts.0).

Spring · any YAMLTeam & BusinessFiles:application.ymlapplication-dev.yamlany other *.yml
application.yml
spring:
  datasource:
    url: jdbc:postgresql://db:5432/shop
    password: change-me
stripe:
  apiKey: sk_test_example
Keys imported from application.yml
KeyValue
spring.datasource.urljdbc:postgresql://db:5432/shop
spring.datasource.passwordchange-me
stripe.apiKeysk_test_example
  • A setting without a value (key: or ~) is imported with an empty value.

Dart config classes

Every getter and constant is imported under its own name: shopApi stays shopApi, and an env.dart download keeps it.

FlutterTeam & BusinessFiles:app_config.dartapp_config_prod.dartany *.dart config class
app_config_staging.dart
import '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';
}
Keys imported from app_config_staging.dart
KeyValue
environmentEnv.staging
shopApihttps://staging-api.example.com
basicAuthTokendXNlcjpjaGFuZ2UtbWU=
enableExperimentalFeaturestrue
appIdswitch (Platform.operatingSystem) { 'android' => 'com.example.shop', _ => '1234567890', }
mapsKeyAIzaExample
  • A value worked out in code (a switch, a Platform check, an enum such as Env.staging, null) is imported exactly as written, and the import lists it so you can check it.
  • String.fromEnvironment('API_URL', defaultValue: '…') imports as API_URL with 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.dart holds 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.

Missing a format?

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

Describe the format or paste the error message, with a small example that uses made-up values. Never paste real secrets.