Node "ENOENT open .env" Missing Env File at Runtime in CI - Fix It
A .env file is local-only and is not committed, so loading it at runtime in CI throws ENOENT. Real CI secrets come from the workflow environment, not a file.
What this error means
A node process or dotenv load throws Error: ENOENT: no such file or directory, open '.env' in CI, because the env file exists only on developer machines.
Error: ENOENT: no such file or directory, open '/home/runner/work/app/app/.env'
at Object.openSync (node:fs:603:3)
at Object.readFileSync (node:fs:471:35)
at Object.config (node_modules/dotenv/lib/main.js:84:35)Common causes
The .env file is gitignored
The env file is not committed (correctly, since it holds secrets), so it is absent on a clean CI checkout.
Hard requiring the file instead of falling back to process.env
Code calls dotenv in a way that throws when the file is missing rather than reading from the real environment.
How to fix it
Provide variables via workflow env
- Set the required variables in the workflow env or from secrets.
- Let the code read process.env directly in CI.
- run: node server.js
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}Make dotenv loading optional
- Load .env only if present and fall back to process.env otherwise.
import { existsSync } from 'node:fs';
if (existsSync('.env')) (await import('dotenv')).config();How to prevent it
- Treat process.env as the source of truth, load .env only as an optional local convenience, and supply CI variables through workflow env or secrets.