Checklist lỗi .env thường gặp | Quote, khoảng trắng, thiếu key

(Cập nhật: 19 tháng 7, 2026 ) .env dotenv environment variables checklist Node.js Docker
Kết luận

Hầu hết lỗi .env không phải “dotenv hỏng” — mà là space quanh =, quote lệch, thiếu key so với .env.example, hoặc process đang đọc file khác (.env.local / Docker env_file). Sửa theo checklist dưới trước khi đụng code business. Giữ secret khỏi git; chỉ commit template.

Lead nhắn: “Clone về chạy không được — chắc thiếu dependency.” Bạn npm i lại lần nữa. Thật ra process.env.DATABASE_URLundefined vì key trong .env.example chưa bao giờ được copy, hoặc value bị cắt vì dấu " thiếu.

Bài này là checklist lỗi .env thường gặp cho junior, freelance và team outsourcing Việt Nam — nơi onboard hay gửi screenshot .env qua chat và mỗi người paste một kiểu. Tập trung cú pháp + thiếu key + nhầm file, không lan man lý thuyết 12-factor.

Ai nên bookmark

  • Lần đầu setup Node / Nest / Next / Vite có dotenv
  • Nhận repo khách chỉ có .env.example trống trải
  • Docker Compose “mất” biến dù local chạy ổn
  • Review PR: phát hiện .env sắp bị commit

Quy tắc vàng 30 giây

# Đúng
DATABASE_URL=postgres://user:pass@localhost:5432/app
APP_NAME="My App"
FEATURE_FLAG=true

# Sai / rủi ro cao
DATABASE_URL = postgres://...          # space quanh =
APP_NAME=My App                        # space trong value không quote
APP_NAME="My App                       # thiếu đóng quote
SECRET=abc#comment                     # # có thể bị coi là comment
  1. KEY=value — không space quanh =
  2. Value có space / # / ký tự lạ → quote
  3. Comment: ưu tiên dòng riêng bắt đầu bằng #
  4. Mỗi môi trường một file; không commit secret
  5. Onboard = copy .env.example.env rồi điền đủ key

Checklist lỗi thường gặp

Triệu chứng → nguyên nhân → sửa
Triệu chứng Nguyên nhân hay gặp Cách sửa
undefined dù đã có dòng trong file Sai tên key / đọc nhầm file / chưa restart Diff với .env.example; restart dev server
Value bị cắt hoặc có dấu " thừa Quote mở/đóng lệch; escape JSON sai Khớp cặp nháy; thử bỏ quote nếu value đơn giản
Key lạ kiểu "API_KEY " Space trước/sau tên hoặc quanh = Viết KEY=value sát nhau
Chỉ fail trên Linux CI CRLF từ Windows; BOM đầu file LF; lưu UTF-8 không BOM
Local OK, container miss Compose env_file / ${VAR} khác dotenv app Kiểm tra env_file + environment trong compose
Lỗi URI / JSON parse Thiếu quote URL; JSON một dòng chưa escape Quote value; validate bằng formatter

In checklist này vào ticket onboard — đỡ hơn giải thích lại mỗi sprint.


1) Khoảng trắng quanh = và trong value

Sai

API_KEY = sk_live_xxx
DB_HOST= localhost

Một số parser giữ space trong tên key (API_KEY ) hoặc value ( localhost). Code của bạn tìm API_KEY → miss.

Đúng

API_KEY=sk_live_xxx
DB_HOST=localhost
APP_TITLE="Staging Shop"

Rule: space trong value → bọc nháy. Space quanh = → xóa.


2) Quote: thiếu, thừa, hoặc lệch kiểu

Tình huốngGợi ý
Số / boolean / slug đơnKhông cần quote: PORT=3000, DEBUG=true
Có spaceNAME="Cafe Ha Noi"
#Bắt buộc quote nếu không muốn bị comment
JSON ngắnCONFIG="{\"a\":1}" — escape \ đúng mức thư viện
Nháy lệch"abc' → parser ăn sang dòng sau

Mẹo debug: log JSON.stringify(process.env.MY_KEY) (trên value giả) để thấy có còn dấu " bị nuốt hay \r ở cuối không. Không log secret production.


3) Thiếu key — lỗi im lặng nguy hiểm nhất

File .env “có đó” nhưng thiếu REDIS_URL trong khi code process.env.REDIS_URL! giả định luôn có. Runtime không báo “missing line 12” — bạn chỉ thấy timeout hoặc fallback sai.

Checklist thiếu key (làm mỗi lần clone)

  1. Mở .env.example (hoặc docs Notion của team)
  2. Liệt kê mọi KEY=
  3. So với .env thật — đánh dấu thiếu / thừa / đổi tên
  4. Biến bắt buộc (DB, auth secret) để trống cố ý → fail fast trong config.ts còn hơn chạy nửa vời

Ví dụ fail-fast (Node):

function required(name: string): string {
  const v = process.env[name];
  if (!v) throw new Error(`Missing env: ${name}`);
  return v;
}

export const dbUrl = required("DATABASE_URL");

Freelance nhận repo khách: 15 phút diff key tiết kiệm nửa ngày đoán bug “API 401” do thiếu JWT_SECRET.


4) Comment, dòng trống, và export thừa

# Good: comment riêng dòng
# Production DB — không commit
DATABASE_URL=postgres://...

# Risky: comment cuối dòng (một số lib cắt, một số giữ nguyên)
MODE=dev # local only

# Sai nếu shell-style lọt vào dotenv thuần
export API_KEY=xxx

Ưu tiên comment đầu dòng. Tránh export trừ khi file dành cho source trong bash. Dòng trống OK; dòng chỉ có space đôi khi tạo key rỗng kỳ lạ — xóa sạch.


5) Nhầm file / nhầm môi trường

FileAi đọc
.envdotenv mặc định nhiều app Node
.env.localNext.js / một số tool — ưu tiên cao, thường gitignore
.env.development / .env.productionFramework load theo NODE_ENV
docker-compose.ymlenv_fileContainer, không phải process trên host
Secret CI (GitHub Actions)Không nằm trong file local

Triệu chứng kinh điển: sửa .env mãi không ăn vì Next đang đọc .env.local cũ. Hoặc PM2/cluster không restart → env cũ còn trong memory.


6) Docker Compose: hai “vũ trụ” env

# .env cạnh compose: dùng cho ${IMAGE_TAG} khi parse file
services:
  api:
    env_file:
      - .env.docker
    environment:
      NODE_ENV: production
      DATABASE_URL: ${DATABASE_URL}
  • ${DATABASE_URL} lấy từ môi trường host / .env mặc định của Compose
  • env_file inject vào container
  • environment: có thể ghi đè

Local npm run dev đọc .env qua dotenv — không chứng minh container thấy cùng bộ key. Checklist: docker compose config (che secret khi paste) và printenv trong container (chỉ tên key).


7) CRLF, BOM, encoding tiếng Việt trong value

  • File tạo trên Windows → CRLF (\r\n). Một số parser để \r dính cuối value → so khớp chuỗi fail ("secret\r" !== "secret").
  • Excel / Notepad “UTF-8 with BOM” → key đầu file thành \uFEFFAPI_KEY.
  • Value tiếng Việt / path có dấu: dùng UTF-8, quote nếu cần; tránh copy từ Word (dấu " cong).

Đồng bộ team: EditorConfig end_of_line = lf cho .env*.


Dùng formatter để lộ dòng lệch

Khi .env 80 dòng paste từ 3 người, mắt thường dễ miss. Dán vào .env Formatter trên Kawa: sort theo key, giữ comment, chạy local trên trình duyệt (không upload) — tiện soi key trùng, khoảng trống, thứ tự lộn xộn trước khi commit .env.example.

🛠️ Kiểm tra định dạng .env ngay tại đây

Workflow gợi ý:

  1. Paste .env.example + bản .env đã che secret
  2. Format/sort → diff bằng mắt dễ hơn
  3. Copy lại template sạch vào repo

Không thay thế secret manager — chỉ giảm lỗi cú pháp và thiếu key.


Case study

A) Outsourcing: “DB sai” hóa ra space

DATABASE_URL= postgres://... (space sau =). Lib giữ space → URI invalid. Dev đổ lỗi Postgres. Sửa một ký tự xong green.

B) Freelance Next.js: sửa không ăn

Khách gửi .env; bạn sửa NEXT_PUBLIC_API_URL. Vẫn gọi staging cũ vì máy còn .env.local gitignore với URL cũ. Xóa/override .env.local mới đúng.

C) CI đỏ, laptop xanh

Key STRIPE_SECRET có trong .env local nhưng chưa khai báo GitHub Actions secrets. Thêm fail-fast required() khiến CI fail rõ “Missing env” thay vì lỗi Stripe khó đọc.


Bảo mật tối thiểu (vẫn trong checklist)

  • .gitignore: .env, .env.*.local (giữ .env.example)
  • Không paste secret vào issue/PR; dùng memo mã hóa ngắn hạn nếu buộc phải gửi tạm, rồi rotate
  • Đã push nhầm → rotate, không chỉ xóa file
  • Production: secret store (CI / vault / platform env), không dựa vào file trên disk shared

Checklist copy-paste trước khi hỏi team

  • Mọi key trong .env.example đều có trong .env
  • Không space quanh =
  • Quote khớp; value có # hoặc space đã được quote
  • Không export, không comment cuối dòng nếu lib team không hỗ trợ
  • LF, không BOM
  • Đúng file (.env vs .env.local vs Compose env_file)
  • Đã restart process / rebuild container
  • Không commit secret; .env.example không chứa key thật

Tóm tắt

Lỗi .env hay gặp nhất là cú pháp nhỏthiếu key im lặng. Sửa checklist trước khi refactor code. Khi cần sắp xếp / soi key nhanh trên trình duyệt: .env Formatter.

Liên kết liên quan