Fait partie de Hébergement par cadricielHébergement · Vite

Pourquoi import.meta.env est undefined après la compilation Vite, et comment corriger.

Vite recopie chaque valeur import.meta.env.VITE_* dans votre JavaScript au moment de vite build. Si la variable n’a pas le préfixe VITE_, si elle n’existe que dans un fichier .env non versionné ou si elle a été définie après la compilation, le paquet contient undefined. Renommez-la, définissez-la là où la compilation s’exécute, puis recompilez.

Faits vérifiés le

Trouvez votre symptôme

Presque tous les cas tombent dans l’une de ces lignes. Les trois premières valent chez n’importe quel hébergeur; les deux dernières tiennent à la façon dont Canner attribue une portée aux variables.

Ce que vous voyezPourquoiCorrectif
import.meta.env.API_URL est undefined partout, même avec vite dev † †Vite n’expose au code navigateur que les variables qui commencent par VITE_ (ou par votre envPrefix)Renommez-la VITE_API_URL. Ne mettez jamais envPrefix à une chaîne vide : Vite le refuse, car toutes les variables seraient exposées
Ça marche en local, undefined après le déploiement †La valeur est dans .env.local ou dans un autre fichier exclu par .gitignore; le serveur de compilation ne l’a jamais reçueDéfinissez-la dans les variables d’environnement de l’hébergeur. Une vraie variable d’environnement a aussi priorité sur tout fichier .env
Vous avez changé la valeur dans le tableau de bord, le site affiche l’ancienne †vite build a remplacé l’expression par une chaîne. Le site en ligne ne lit plus rienRecompilez. Sur Canner, redéployez
Undefined seulement dans les aperçus de demandes de tirage (Canner)La variable a la portée production; les aperçus ne reçoivent que toutes et aperçuDonnez-lui la portée toutes, ou ajoutez une copie aperçu avec la valeur de préproduction
Undefined à chaque déploiement alors qu’elle est définie (Canner)Sa portée est exécution seulement, qui n’atteint jamais une compilationPassez à production ou toutes, puis redéployez

† Les détails sur les concurrents proviennent des pages publiées par chaque fournisseur aux dates indiquées; les prix et forfaits changent, vérifiez auprès du fournisseur avant de décider. `import.meta.env.API_URL` est undefined partout, même avec `vite dev` (2026-10-29) · `import.meta.env.API_URL` est undefined partout, même avec `vite dev` (2026-10-29) · Ça marche en local, undefined après le déploiement (2026-10-29) · Vous avez changé la valeur dans le tableau de bord, le site affiche l’ancienne (2026-10-29)

Ce que vite build fait de la valeur

La documentation de Vite le dit : les constantes sont remplacées statiquement à la compilation. Il n’existe pas d’objet import.meta.env dans le navigateur où chercher une valeur plus tard. La compilation lit la valeur une fois et l’écrit dans le résultat, en texte :

  • vite build s’exécute en mode production : il charge .env, .env.local, .env.production et .env.production.local. Les variables déjà présentes dans l’environnement au démarrage de Vite passent avant tous ces fichiers.
  • Le même remplacement se fait dans index.html : %VITE_API_URL% devient la valeur au moment de la compilation.
  • Tout ce qui porte le préfixe VITE_ aboutit dans du JavaScript public. La documentation de Vite déconseille d’y mettre des clés d’API. Gardez les secrets côté serveur.
// src/api.ts, what you write
const base = import.meta.env.VITE_API_URL;

// dist/assets/index-<hash>.js, what ships after
// VITE_API_URL=https://api.example.ca vite build
const base = "https://api.example.ca";

// Check what a build actually contains:
grep -r "api.example.ca" dist/assets

Définir les variables Vite sur Canner

Canner exécute votre script build avec les variables du projet dans l’environnement : Vite les lit comme n’importe quelle variable d’environnement. Le journal de compilation le confirme par une ligne comme [canner] wrote 6 env var(s) to .env.production (build phase). Définissez les valeurs dans l’onglet Variables d’environnement du projet, pas dans un .env.production versionné. La page Vite de la documentation couvre le reste du déploiement.

Une valeur modifiée s’applique au déploiement suivant, puisque l’ancien paquet contient l’ancienne chaîne. Deux points moins évidents tirés de la documentation sur les variables d’environnement :

  • Sensible masque une valeur dans le tableau de bord. Pas aux visiteurs : une valeur VITE_ sensible est quand même écrite dans le paquet public.
  • Exécution seulement tient un secret à l’écart de la compilation. C’est justement pourquoi une variable VITE_ avec cette portée est toujours undefined.

Exposer une valeur de compilation sans le préfixe

L’option define de Vite remplace un nom global par une valeur JSON pendant la compilation. Servez-vous-en pour des valeurs choisies délibérément, comme un bandeau d’aperçu ou un numéro de version dans vos rapports d’erreur :

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// CANNER_ENV is "production" or "preview" during a Canner build.
// It has no VITE_ prefix, so pass it through define, by name.
export default defineConfig({
  plugins: [react()],
  define: {
    __APP_ENV__: JSON.stringify(process.env.CANNER_ENV ?? "local"),
    __COMMIT__: JSON.stringify(process.env.CANNER_COMMIT_SHA ?? "dev"),
  },
});

Une seule compilation pour plusieurs environnements

Des valeurs fixées à la compilation, c’est une compilation par environnement. Pour promouvoir en production le dist/ exact que vous avez testé en préproduction, les valeurs ne peuvent pas y être intégrées. Il faut les récupérer ou les injecter au chargement de la page.

ApprocheOù vit la valeurPour la changerAttention
Une compilation par environnement (VITE_*) †Dans le paquet JavaScriptUne recompilationLes secrets sont visibles par tous
config.json récupéréUn fichier à côté d’index.htmlRemplacer un fichierUn fichier absent renvoie index.html chez un hébergeur d’appli monopage, et res.json() échoue avec Unexpected token '<'
window.__ENV écrit par un serveurL’environnement du serveur au démarrageUn redémarrageVous exploitez désormais un serveur; échappez < dans le JSON

† Les détails sur les concurrents proviennent des pages publiées par chaque fournisseur aux dates indiquées; les prix et forfaits changent, vérifiez auprès du fournisseur avant de décider. Une compilation par environnement (`VITE_*`) (2026-10-29)

Méthode 1 : récupérer config.json avant le démarrage

Votre étape de déploiement écrit un config.json différent par environnement et ne touche pas au JavaScript. Vérifiez le type de contenu : un hébergeur d’appli monopage répond à tout chemin inconnu par index.html et un code 200, si bien qu’une configuration absente ressemble à une requête réussie.

// public/config.json is copied to dist/ untouched
{ "apiUrl": "https://api.staging.example.ca" }

// src/main.ts
const res = await fetch("/config.json", { cache: "no-store" });
const type = res.headers.get("content-type") ?? "";
if (!res.ok || !type.includes("json")) {
  // An SPA host answers a missing file with index.html
  throw new Error("config.json is missing from this deploy");
}
export const config: { apiUrl: string } = await res.json();

Méthode 2 : injecter window.__ENV depuis un serveur

Placez <!--app-env--> dans le <head> d’index.html; un petit serveur le remplit à partir de son propre environnement au démarrage. N’y mettez que des valeurs publiques : chaque visiteur peut lire la balise script.

// server.mjs: serves dist/ and writes public values into index.html
import express from "express";
import { readFileSync } from "node:fs";

const env = { apiUrl: process.env.API_URL }; // public values only
const html = readFileSync("dist/index.html", "utf8").replace(
  "<!--app-env-->",
  "<script>window.__ENV=" + JSON.stringify(env).replace(/</g, "\\u003c") + "</script>",
);

const app = express();
app.use(express.static("dist", { index: false }));
app.use((_req, res) => res.type("html").send(html));
app.listen(process.env.PORT || 3000);

Laquelle choisir sur Canner

Sur Canner, tout changement de variable s’applique au déploiement suivant, et chaque déploiement exécute la compilation. La configuration à l’exécution ne vous épargne donc pas de compilation ici. Elle vaut la peine si le même artefact est déployé ailleurs aussi, ou si votre appli a déjà un serveur Node.

Le plus simple : un projet Canner par environnement. Un projet de préproduction et un projet de production, qui peuvent être reliés au même dépôt, chacun avec ses valeurs VITE_. Le forfait Démarrage inclut des projets illimités. Un projet Démarrage se met en veille après trois heures d’inactivité, ce qui convient en général à la préproduction.

Si vous choisissez la méthode 2, Canner détecte un projet qui embarque son propre serveur Node avec le client compilé, et exécute le serveur au lieu de servir dist/ en statique. D’autres guides sont dans hébergement par cadriciel.

Questions

Pourquoi import.meta.env fonctionne-t-il en développement mais pas en production?

En développement, Vite lit les fichiers .env sur votre poste, .env.local compris. En production, la valeur doit exister là où vite build s’exécute. Un fichier exclu par Git n’y arrive jamais, et une variable sans préfixe VITE_ n’est jamais exposée au code navigateur.

Peut-on changer une variable d’environnement Vite sans recompiler?

Pas une variable VITE_ : sa valeur est écrite dans le JavaScript pendant la compilation. Si elle doit changer sans compilation, déplacez-la dans un config.json récupéré ou un window.__ENV injecté par un serveur.

Peut-on mettre une clé d’API dans une variable VITE_?

Non. Tout ce qui porte le préfixe VITE_ aboutit dans du JavaScript public, lisible par n’importe qui. Appelez l’API depuis un serveur que vous contrôlez et gardez-y la clé.

Faut-il redéployer sur Canner après avoir changé une variable VITE_?

Oui. Les changements de variables s’appliquent au déploiement suivant, et c’est la compilation de ce déploiement qui écrit la nouvelle valeur dans le paquet. Voir variables d’environnement.

Déployez votre appli Vite depuis Montréal.

Définissez vos variables VITE_ dans le tableau de bord, poussez, et Canner compile et sert le paquet.