flutenv

Secure, zero-friction environment variable injection for Flutter. > Stop typing --dart-define flags. Stop bundling secrets in your APK.


Overview

flutenv is a global Dart CLI tool that wraps the flutter command. It automatically reads your .env file and converts every key-value pair into a --dart-define argument. It is a drop-in replacement for flutter run, flutter build, and any other subcommand β€” with zero configuration required.

# Before flutenv
flutter run \
  --dart-define=API_KEY=abc123 \
  --dart-define=API_URL=https://api.example.com \
  --dart-define=FEATURE_FLAG=true

# After flutenv
flutenv run

πŸ›‘ The "Plaintext Asset" Vulnerability

Why flutter_dotenv is Unsafe for Production

A common pattern is to use flutter_dotenv by adding your .env to pubspec.yaml assets. This approach ships your secrets as a plain text file inside your app bundle.

Since an APK or IPA is simply a ZIP archive, anyone can extract it and read your keys:

unzip build/app/outputs/flutter-apk/app-release.apk
cat assets/.env
# API_URL=https://myapi.com
# API_KEY=super_secret_key   ← Exposed to the world

The flutenv Comparison

Feature flutter_dotenv (Assets) flutenv (--dart-define)
Storage Plaintext file in APK Compiled into the Binary
Access Async Runtime Load Synchronous const
Security ❌ Easy to Reverse-Engineer βœ… Obfuscation Friendly
DX Easy Easy (with flutenv)

The Solution: Compile-Time Injection

Flutter provides --dart-define to inject values at build time. Values are embedded directly into the binary, making them significantly harder to extract, especially when using --obfuscate.

flutenv bridges the gap between the familiar .env file and the secure --dart-define mechanism. It reads your .env locally, but never bundles it into your app.


Installation

# Install from pub.flutter-io.cn
dart pub global activate flutenv

Ensure the Dart pub cache binary directory is on your PATH. Dart will display a reminder if it isn't during activation.


Usage

flutenv acts as a transparent proxy. It forwards all commands, flags, and interactive signals (like r for hot reload) to the Flutter CLI.

# Project setup & security check
flutenv init

# Standard development
flutenv run -d chrome
flutenv run --release

# Building (Secrets are injected into the compiled binary)
flutenv build apk --release --obfuscate --split-debug-info=./debug

# Testing
flutenv test

# Manual overrides on the CLI take precedence over .env
flutenv run --dart-define=API_KEY=temporary_override

flutenv init

Run flutenv init to audit your project security:

  1. Adds .env to .gitignore β€” Prevents committing secrets.
  2. Scans pubspec.yaml β€” Warns if .env is listed under assets:, preventing accidental leaks.

Accessing Variables in Dart

⚠️ IMPORTANT: You must use the const keyword. Because variables are injected at compile-time, final or var will not work and will return the default value.

// βœ… Correct
const apiKey = String.fromEnvironment('API_KEY');
const isPremium = bool.fromEnvironment('IS_PREMIUM', defaultValue: false);

// ❌ Incorrect (will not receive injected values)
final apiUrl = String.fromEnvironment('API_URL');

How It Works

$ flutenv run -d chrome

 πŸ“¦ Reading .env from current directory...
 πŸ›   Converting 5 keys to --dart-define flags...
 πŸš€ Running: flutter run -d chrome
             --dart-define=API_KEY=*** --dart-define=API_URL=*** ...
  1. Parses .env (handles quotes, comments, and values with = signs).
  2. Skips any keys already supplied manually via the command line.
  3. Spawns the flutter process with inherited stdio, ensuring Hot Reload works perfectly.

License

MIT Β© 2026

Libraries

flutenv