什么是 .env 文件?
.env 文件是一个用来保存环境变量的纯文本配置文件。它通常按 KEY=value 的形式一行记录一个键值对,让程序在启动时读取数据库地址、API 密钥、端口等配置,而不必把真实值写进源代码。

你可以把 .env 理解为项目的一张“私密配置单”:代码只知道要读取 API_KEY 或 DB_URL,至于它们在当前环境中具体是什么值,则由外部配置决定。
它主要解决两类问题:
- 配置会随环境变化:本地、测试和生产环境的数据库地址、服务端口往往不同。
- 敏感值不应写进代码:密码、访问令牌和第三方 API 密钥不应随着源码传播。
一句话总结:.env 的核心价值是把会变化或不应公开的配置与代码分离。
.env 文件长什么样?
一个常见的 .env 文件如下:
# 第三方服务
API_KEY=sk-example-only
# 数据库
DB_HOST=localhost
DB_PORT=5432
DB_USER=app_user
DB_PASSWORD="replace-with-your-local-password"
# 应用配置
DEBUG=false

等号左边是变量名,右边是变量值。变量名通常使用大写字母和下划线,例如 DB_HOST;以 # 开头的行是注释。
.env 的文件名以点开头,因此在 Linux 和 macOS 的文件管理器中通常默认隐藏,可以用 ls -la 查看。Windows 是否隐藏取决于文件属性、资源管理器设置和所用工具,文件名前的点本身不等于 Windows 的“隐藏”属性。
还要注意:.env 并不是一项只有一种语法实现的正式标准。不同语言和工具对引号、转义、多行值、变量展开的支持可能不同,应以项目实际使用的加载器文档为准。
为什么不能把密码和地址硬编码在源码里?
硬编码是指把配置值直接写进代码。例如:
const databaseUrl = 'postgresql://user:password@localhost:5432/app';
const apiKey = 'sk-real-secret';

这种写法有两个直接后果:
- 换环境就要改代码:从本地切到测试或生产环境时,需要修改地址、账号或端口,容易产生漏改和错误提交。
- 源码泄露会带走密钥:代码一旦被推送到 GitHub、GitLab、日志、制品库或共享压缩包,写在其中的秘密也会一起传播。
改用环境变量后,代码只保留变量名:
const databaseUrl = process.env.DB_URL;
const apiKey = process.env.API_KEY;
这样同一份代码可以在不同环境中读取不同值,真实配置也有机会使用独立的权限和分发方式管理。
不过,.env 只是降低硬编码风险,不是加密工具。文件中的值仍然是明文,任何能读取该文件或进程环境的人都可能看到它。
程序如何读取 .env 文件?
程序通常通过 dotenv 一类加载器,在启动阶段读取 .env、解析键值对,再把它们放入当前进程的环境变量中。业务代码随后通过统一接口读取变量,不需要知道值来自文件、操作系统还是部署平台。

以 Node.js 和 dotenv 为例:
npm install dotenv
// app.js
import 'dotenv/config';
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('缺少必需的环境变量 API_KEY');
}
加载过程可以概括为五步:
- 项目启动并执行入口脚本。
- 加载器找到指定的
.env文件。 - 加载器把文件内容解析为键值对。
- 键值对进入当前进程的环境变量。
- 代码通过
process.env.API_KEY等接口读取值。
Node.js 20.6.0 起也提供了 --env-file 命令行选项,例如 node --env-file=.env app.js。Next.js、Vite、Django、Laravel 等框架也有各自的加载约定,因此不是每个项目都需要手动安装 dotenv。
.env 如何让同一套代码运行在不同环境?
环境变量让代码保持不变,把差异交给运行环境决定。数据库连接最能说明这个原则。

代码始终读取同一个变量:
const databaseUrl = process.env.DB_URL;
本地开发可以使用:
DB_URL=postgresql://app:local-password@localhost:5432/app
生产部署则由平台注入另一个值:
DB_URL=postgresql://app:<production-secret>@prod-db.internal:5432/app
| 方式 | 换环境时改什么 | 密钥是否进入源码 | 适合场景 |
|---|---|---|---|
| 硬编码 | 修改并重新提交代码 | 是 | 不推荐 |
本地 .env | 修改本地配置文件 | 否,前提是正确忽略 | 本地开发、个人实验 |
| 系统或云平台变量 | 修改启动环境或控制台配置 | 否 | 测试、预发布、生产部署 |
| 密钥管理服务 | 修改受控的密钥版本或引用 | 否 | 对审计、轮换和权限有要求的生产系统 |
生产环境并不一定需要保存一份真实 .env 文件。容器编排平台、CI/CD 系统和云服务通常可以在运行时注入变量,减少明文文件散落在服务器上的风险。
团队为什么需要 .env.example?
真实 .env 不应提交到仓库,但团队成员仍需知道项目依赖哪些变量。.env.example 就是可提交的配置模板:它保留变量名和非敏感示例,不包含真实密码或令牌。

例如:
# .env.example
APP_PORT=3000
DB_URL=postgresql://user:password@localhost:5432/app
API_KEY=replace-with-your-api-key
新成员获取代码后,可以复制模板:
cp .env.example .env
然后只在本地 .env 中填写真实值。.env.example 还应与代码同步维护:新增必需变量时更新模板,删除变量时也及时清理。
模板不应只列出名字。对端口、布尔值、枚举和 URL 等配置,最好给出合法示例或注释,让新成员能判断格式;对秘密值则使用明确占位符,避免放入任何可用凭据。
.env 有哪些常见格式规则?
.env 的基础格式简单,但解析细节取决于加载器。跨项目最稳妥的写法是使用清晰的变量名、显式引号和少量注释。

常见规则包括:
- 一行一个键值对:使用
KEY=value,等号左边是变量名。 - 用
#写注释:整行注释最容易被不同加载器一致处理。 - 必要时使用引号:值包含空格、
#或特殊字符时,用引号明确边界。 - 变量名使用大写和下划线:例如
MAX_RETRY_COUNT,方便与普通代码变量区分。 - 不要在等号两侧随意加空格:部分解析器会修剪空格,部分工具的行为可能不同。
APP_NAME="My Service"
MAX_RETRY_COUNT=3
ENABLE_CACHE=true
CALLBACK_URL=https://example.com/callback
从环境变量读取的值通常都是字符串。"false" 不会自动成为 JavaScript 的布尔值,"3000" 也不会自动成为数字;应用应在启动时完成类型转换和校验,并在配置无效时尽早报错。
使用 .env 必须避开哪些安全坑?
.env 的最大风险不是格式错误,而是把明文秘密传播到了不该出现的地方。下面三条是必须遵守的安全红线。

红线一:不要把真实 .env 提交到代码仓库
.env 不会自动被 Git 忽略,必须明确写入 .gitignore:
.env
.env.*
!.env.example
如果秘密已经提交过,仅在后续删除文件并不够,因为它仍可能存在于 Git 历史、派生仓库和缓存中。应立即撤销或轮换对应密钥,再评估是否需要清理历史记录。
红线二:不要把秘密打包进镜像或前端产物
构建 Docker 镜像时应配置 .dockerignore,避免把本地 .env 复制进构建上下文和镜像层。部署时再通过运行参数、平台变量或 Secret 机制注入配置。
前端变量尤其需要谨慎。带有 NEXT_PUBLIC_、VITE_ 等公开前缀的值会进入浏览器可下载的 JavaScript;即使变量最初来自 .env,构建后也不再是秘密。真正的 API 私钥只能由服务端使用。
红线三:不要通过聊天或邮件随意转发生产密钥
聊天记录、邮件、截图、工单和日志都可能被长期保存或转发。团队应使用具备访问控制、审计和轮换能力的密码管理器或密钥管理服务分发生产秘密。
此外,还应限制 .env 的文件读取权限、避免在错误日志中打印完整环境变量,并定期轮换长期凭据。
.env 是环境变量的唯一来源吗?
不是。.env 只是环境变量的一种便捷来源,本地开发中最直观,但操作系统、Shell、CI/CD、Docker、Kubernetes 和云平台都可以直接提供环境变量。

常见来源包括:
| 来源 | 典型写法或位置 | 主要用途 |
|---|---|---|
| 当前 Shell | export API_KEY=value | 临时调试、脚本运行 |
.env 文件 | 项目本地文件 | 本地开发 |
| npm 或启动命令 | API_KEY=value npm start | 单次启动覆盖 |
| Docker / Compose | -e、env_file、Secret | 容器运行配置 |
| CI/CD 平台 | Repository Secrets、Variables | 构建和部署 |
| 云平台控制台 | Environment Variables、Secrets | 托管应用和生产环境 |
| 密钥管理服务 | Secret Manager、Vault、KMS 相关服务 | 权限控制、审计、版本和轮换 |
当同名变量来自多个来源时,谁覆盖谁由运行时和加载器决定。例如,许多 dotenv 用法默认不会覆盖进程中已经存在的变量,但框架对 .env.local、.env.production 等文件可能有自己的优先级。不要凭经验猜测,应查阅当前工具文档并用启动校验确认最终值。
怎样在项目中正确引入 .env?
最小可行流程只有三步:把本地秘密放进 .env,让 Git 和构建工具忽略它,再提交不含真实值的 .env.example。

可以按下面的清单执行:
- 创建
.env,写入本地运行所需的配置。 - 将
.env和环境变体加入.gitignore。 - 在
.dockerignore等构建忽略文件中排除本地配置。 - 创建并提交
.env.example,只保留变量名、注释和安全示例。 - 在应用启动时校验必需变量、类型和允许值。
- 在生产环境使用平台变量或密钥管理服务,并建立轮换流程。
配置与代码分离的目标不是“把秘密换个文件藏起来”,而是让配置拥有独立的注入方式、访问权限和生命周期。
常见问题
.env 文件可以提交到 GitHub 吗?
真实 .env 通常不应提交到 GitHub,包括私有仓库。私有仓库也可能因成员权限、日志、派生仓库或误操作导致秘密扩散。应提交 .env.example,并通过受控渠道提供真实值。
把 .env 加入 .gitignore 就绝对安全吗?
不绝对安全。.gitignore 只能阻止尚未被 Git 跟踪的文件进入后续提交,不能删除已经提交的历史,也不能阻止文件被复制、打印到日志或打进构建产物。已经泄露的密钥应立即轮换。
.env 和环境变量有什么区别?
环境变量是进程运行时读取的键值配置;.env 是保存这些键值的一种文本文件。加载器把 .env 内容写入进程环境后,程序读取到的是环境变量,而不是直接依赖文件格式。
.env、.env.local 和 .env.production 有什么区别?
它们通常代表通用、本地和生产配置,但具体加载顺序不是统一标准,而是由 Next.js、Vite 等框架规定。使用前应查看对应框架的加载规则,避免错误覆盖。
前端项目可以把 API Key 放进 .env 吗?
只有本来就允许公开的值才可以进入前端构建。任何被编译进浏览器代码的变量都能被用户查看,不能依靠 .env 隐藏私钥、数据库密码或服务端令牌。
生产环境应该使用 .env 文件吗?
小型或受控部署可以使用权限严格的 .env 文件,但云平台变量、容器 Secret 或专用密钥管理服务通常更适合生产环境,因为它们更容易实现访问控制、审计和轮换。
总结
.env 是保存环境变量键值对的纯文本文件,它通过把配置与代码分离,解决多环境切换和敏感值硬编码的问题。程序在启动时加载这些值,业务代码始终读取稳定的变量名。
真正需要记住的不是文件名,而是三条实践:真实秘密写入本地 .env,.env 加入忽略规则,仓库只提交 .env.example。 对生产系统,再用平台变量或密钥管理服务补上权限、审计和轮换,才能形成完整的配置安全方案。

