Is the VITE_ prefix convention enough to keep secrets out of a Vite client bundle?
0 reputation · 03 Jan 2021, 09:02 UTC
0 reputation · 03 Jan 2021, 09:02 UTC
Our team ships a Vite-built SPA and stores configuration in .env files per mode (.env.production, .env.staging). I understand Vite only inlines variables prefixed with VITE_ into import.meta.env, and that anything with that prefix ends up readable in the shipped JavaScript. Files in public/ are also copied verbatim to the output root with no access control.
The unresolved decision is process, not syntax: the VITE_ prefix is a naming convention, not a guardrail. A developer can accidentally prefix an API secret, or reuse a variable name across mode files so a value that was safe in one environment leaks in another. Similarly, a sensitive file dropped into public/ persists across builds until manually removed.
Assume a recent Vite major version; I know env inlining behavior has changed across releases and differs between dev, build, and SSR contexts, so answers should note version assumptions.
1. Do teams rely on the prefix convention alone, or is a build-time check (e.g., scanning dist/ for secret patterns in CI) a common complement?
2. Is there a documented way to make a build fail when an unprefixed secret-like variable is referenced from client code?
3. For public/, is manual audit the only option, or is there a supported mechanism to exclude specific files from the copy step?
35775 reputation · 03 Jan 2021, 12:51 UTC
No. The VITE_ naming convention only tells Vite which variables to inline; it does not prevent a developer from accidentally prefixing a secret, and it offers no guard against sensitive files placed in public/. Additional checks are required to keep secrets out of the shipped bundle.
import.meta.env.VITE_* reference with the variable’s value during vite build. If the variable name starts with VITE_ but holds a secret, that secret becomes part of the final JavaScript and is visible to anyone inspecting the bundle.public/ are copied verbatim to the output root with no filtering, so a sensitive file dropped there will persist across builds until manually removed.import.meta.env is accessed with a name not in an approved list (e.g., only VITE_API_URL, VITE_APP_VERSION).dist/. Example command:
# Adjust patterns to your secrets
if grep -rE "API_KEY|TOKEN|SECRET|PASSWORD" dist/; then
echo "Potential secret found in bundle"
exit 1
fi
vite-plugin-env-only (or similar) can be configured to fail the build if any non‑VITE_ variable is referenced.public/ – treat the folder as public assets only. If you need to exclude specific files, move them outside public/ before the build (e.g., a script that temporarily renames or deletes them) or use a custom Vite plugin that filters the copy step.Vite provides no built‑in exclude mechanism for public/. The safest approach is to keep the folder free of sensitive files and to add a CI step that verifies no disallowed files appear after the build:
# Example: ensure no .key or .pem files are present
if find dist -type f -name "*.key" -o -name "*.pem" | grep -q .; then
echo "Sensitive file found in public output"
exit 1
fi
Are you building for a client‑only SPA, or are you also using Vite’s SSR or library mode? In SSR/library modes the env inlining behavior differs, and additional checks may be needed for server‑side bundles.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.