Developer Basics

What is a .env File
and How to Use It Safely

The right way to keep API keys, database passwords and secrets out of your source code — and out of Git.

7 min read·Updated Mar 2026

What is a .env file and how to use it safely is one of those fundamentals that every developer needs but few resources explain clearly. The short version: a .env file is where you store secrets — API keys, database passwords, tokens — so they live outside your code and never end up in Git. Here's the complete guide.

What is a .env File?

A .env file is a plain text file containing key-value pairs, one per line. Each line defines an environment variable that your application reads at runtime:

# .env — never commit this file
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
STRIPE_SECRET_KEY=sk_live_abc123xyz
OPENAI_API_KEY=sk-proj-abc123
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
SENDGRID_API_KEY=SG.abc123
DEBUG=false
APP_ENV=production

Your application loads this file on startup and the values become available as environment variables — the same way variables set in your shell or on your hosting platform are available. The key insight is that secrets live in the file, not in your code.

The Problem It Solves

Without a .env file, developers often do this:

❌ What not to do
# Hardcoded in source — terrible
import openai
openai.api_key = "sk-proj-abc123"

# In a config file — also bad
config = {
  "db_password": "hunter2",
  "stripe_key": "sk_live_xyz"
}
✅ The right way
# Read from environment
import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")
db_url = os.getenv("DATABASE_URL")

Hardcoded secrets end up in Git. Once they're in Git history, they're there permanently — even if you delete the file later. And if your repo is public, bots will find the key within seconds of the push.

How to Use .env Files by Language/Framework

Python

pip install python-dotenv
from dotenv import load_dotenv
import os

load_dotenv()  # reads .env from current directory

api_key = os.getenv("OPENAI_API_KEY")
db_url  = os.getenv("DATABASE_URL")

Node.js

npm install dotenv
// At the very top of your entry file
require('dotenv').config();

const apiKey = process.env.STRIPE_SECRET_KEY;
const dbUrl  = process.env.DATABASE_URL;

Django

pip install django-environ
# settings.py
import environ
env = environ.Env()
environ.Env.read_env()  # reads .env

SECRET_KEY   = env('DJANGO_SECRET_KEY')
DATABASE_URL = env('DATABASE_URL')

PHP

composer require vlucas/phpdotenv
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

$dbPassword = $_ENV['DB_PASSWORD'];
$stripeKey  = $_ENV['STRIPE_SECRET_KEY'];

Ruby on Rails

Rails loads .env automatically in development via the dotenv-rails gem:

# Gemfile
gem 'dotenv-rails', groups: [:development, :test]

The .gitignore Rule — Non-Negotiable

Your .env file must be in .gitignore. Add this before your first commit:

# .gitignore
.env
.env.*
.env.local
.env.*.local
!.env.example

The ! before .env.example means "exclude from the exclusion" — it allows the example file to be committed while blocking all real .env files.

Already committed .env by accident?

Adding to .gitignore after the fact stops future commits but does not remove the file from history. See How to Remove API Keys From Git History for the full fix. Revoke any exposed secrets immediately.

The .env.example Pattern

Always create a .env.example file alongside your .env. It shows other developers what variables are needed, without exposing real values:

# .env.example — safe to commit, no real secrets
DATABASE_URL=postgresql://user:password@localhost:5432/myapp_dev
STRIPE_SECRET_KEY=sk_live_your_key_here
OPENAI_API_KEY=sk-proj-your_key_here
AWS_ACCESS_KEY_ID=your_access_key_id
DEBUG=true
APP_ENV=development

When a new developer clones the repo they run cp .env.example .env and fill in their own values.

.env Best Practices

Practice Why
Never commit .envSecrets in Git are permanent — even deleted files remain in history
Always create .env.exampleDocuments what variables are needed without exposing values
Use different values per environmentDev, staging and production should have separate keys with separate permissions
Never log env var valuesLogs containing secrets are a data breach waiting to happen — sanitize before sharing
Use a secrets manager in productionAWS Secrets Manager, Vercel env vars, Railway, Heroku config vars — not a .env file on the server
Validate on startupUse env.required() patterns to fail fast if a required variable is missing, rather than failing silently later

Production: Don't Use a .env File on the Server

A .env file is a development convenience. In production, use your platform's built-in environment variable management — it's more secure, auditable, and doesn't require deploying a secrets file:

Vercel
Project Settings → Environment Variables
Netlify
Site Configuration → Environment Variables
Railway
Project → Variables
Heroku
Settings → Config Vars
AWS
Secrets Manager or Parameter Store
Docker
--env-file flag or Docker Secrets

If a Secret Ends Up in Your Logs

Environment variables can leak into application logs — database connection strings appear in ORM errors, API keys appear in failed request logs, and full .env contents can be printed by misconfigured debug modes. Before sharing any log with a colleague, StackOverflow or an AI assistant, run it through a sanitizer.

Sanitize Logs Before Sharing

Strip API keys, database URLs and credentials from logs in seconds. 100% client-side.

Open Log Sanitizer — Free →

FAQ

What is a .env file? +

A plain text file containing environment variable declarations — key-value pairs like API_KEY=abc123. It keeps secrets out of source code so they are never committed to Git. Loaded at runtime by a library like python-dotenv or dotenv for Node.

Should I commit my .env file to Git? +

Never. Add .env to .gitignore before your first commit. If you accidentally commit it, see How to Remove API Keys From Git History. Commit a .env.example with placeholder values instead.

How do I load a .env file in Python? +

Install python-dotenv with pip, then call load_dotenv() at the top of your app. Access values with os.getenv('VARIABLE_NAME').

What is the difference between .env and .env.example? +

.env contains your real secrets and must never be committed. .env.example is a template with placeholder values — it is safe to commit and documents what variables other developers need to configure.

Can API keys in .env files end up in logs? +

Yes. ORM errors log database connection strings (which include passwords). Failed API requests log the URL with auth headers. Django debug mode can print full environment variables. Always sanitize logs before sharing them — use the Log Sanitizer before pasting logs into ChatGPT or StackOverflow.

Related