# Environnements et variables

Un projet Bastide sert son application dans un ou plusieurs environnements, et chacun reçoit ses propres variables d'environnement. Cette page explique les genres d'environnement, la différence entre une variable visible et un secret, et la façon de les écrire depuis la console, un agent, la ligne de commande ou l'API.

## Les environnements

Un environnement est un lieu de service : il a son adresse, ses déploiements et ses variables. Quatre genres existent dans le modèle.

| Genre | Valeur dans l'API | Comment il naît |
| --- | --- | --- |
| Production | `production` | Avec le projet, toujours, et un seul par projet. |
| Prévisualisation | `preview` | À la poussée d'une branche ou à la demande : voir [Prévisualisations](previews.md). |
| Préproduction | `staging` | Pas encore disponible : aucune opération ne crée cet environnement aujourd'hui. |
| Personnalisé | `custom` | Pas encore disponible : aucune opération ne crée cet environnement aujourd'hui. |

La grille tarifaire prévoit des environnements personnalisés à partir du palier Standard (2 en Standard, 10 en Pro et en Souverain). Tant que leur création n'est pas servie, un projet travaille avec sa production et ses prévisualisations.

Chaque environnement porte un identifiant `env_…`. C'est lui qu'exigent la lecture des variables, le déploiement et la restauration. La seule façon de l'apprendre est de lister les environnements du projet.

### États d'un environnement

La carte **Environnements** de la **Vue d'ensemble** du projet montre, pour chaque environnement, le commit qu'il sert et son état.

- **Épinglé** : l'environnement sert une version restaurée et ne suit plus les poussées. Voir [Restaurer](restore.md).
- **Isolé · bifurcation** : une prévisualisation ouverte depuis une bifurcation du dépôt. Elle ne reçoit aucune variable sensible.
- **En veille** : l'environnement dort faute de trafic et se réveille à la requête suivante.
- **supprimé le …** : la date à laquelle une prévisualisation sera retirée.

Lever l'épinglage remet en service le dernier déploiement sain et fait de nouveau suivre les poussées. C'est une promotion, réservée au rang Mainteneur : menu « ⋯ » de la ligne, puis **Lever l'épinglage**, ou l'outil `environment_unpin`.

## Variables et secrets

Une variable a un nom, une valeur et une sensibilité.

- **Visible** : la valeur se relit, par qui a le rang suffisant (voir le tableau plus bas).
- **Secret** : la valeur est chiffrée à l'écriture et ne se relit jamais, ni dans la console, ni par l'API, ni par un agent, quel que soit le rang. Un secret se remplace : on écrit une nouvelle valeur sous le même nom.

Par défaut, une variable écrite en production est un secret ; ailleurs, elle est visible. Vous pouvez choisir l'autre réglage à chaque écriture.

L'opération `secret.reveal` existe au registre pour que la demande soit refusée nommément et journalisée : elle n'est autorisée à aucun rôle. Une lecture qui nomme un secret reçoit le refus `secret_never_read`.

### Quand une variable prend effet

Une modification prend effet au prochain déploiement de l'environnement. La version en ligne garde le jeu de variables avec lequel elle a été construite jusque-là. Après avoir écrit une variable, redéployez : voir [Déployer](deploy.md).

### Noms autorisés

Un nom commence par une lettre majuscule, puis ne contient que des majuscules, des chiffres et des tirets bas, 64 caractères au plus. Il se lit tel quel dans le code, par exemple `process.env.NEXT_PUBLIC_SITE_URL`.

Certains noms sont refusés à l'écriture, parce que l'interpréteur ou l'éditeur de liens les lit avant le programme et qu'ils changeraient le comportement de l'image sans laisser de trace dans le plan de construction :

```
BASH_ENV  DYLD_INSERT_LIBRARIES  DYLD_LIBRARY_PATH  ENV  GIT_EXTERNAL_DIFF
GIT_SSH_COMMAND  IFS  LD_AUDIT  LD_LIBRARY_PATH  LD_PRELOAD  NODE_EXTRA_CA_CERTS
NODE_OPTIONS  PATH  PERL5OPT  PYTHONPATH  PYTHONSTARTUP  RUBYOPT  SHELL  SSL_CERT_FILE
```

La suppression d'une variable portant l'un de ces noms reste possible.

### Héritage

Une prévisualisation hérite des variables de la préproduction du projet, quand elle existe : une variable propre à la prévisualisation masque celle du même nom héritée. La production, la préproduction et un environnement personnalisé n'héritent de rien. L'inventaire dit, pour chaque variable, si elle est propre à l'environnement ou héritée, et de quel environnement.

### Variables posées par la plateforme

- `PORT` : le port sur lequel l'application doit écouter, posé dans le conteneur.
- `NODE_ENV` : vaut `production` dans les images Node.js que la plateforme construit.
- `DATABASE_URL` et `DIRECT_URL` : quand le projet a sa base PostgreSQL, la plateforme les pose sur l'environnement avant la construction. `DATABASE_URL` passe par le mutualiseur de connexions en mode transaction ; `DIRECT_URL` en mode session, avec une seule connexion, pour les outils de migration comme `prisma migrate`. L'inventaire les marque « Fournie par Bastide ».

Votre propre valeur l'emporte toujours. Si vous écrivez `DATABASE_URL`, la variable devient la vôtre et la plateforme n'y touche plus. Un dépôt configuré pour SQLite garde sa `DATABASE_URL`, et une prévisualisation isolée ne reçoit aucune des deux adresses.

### Variables requises par le dépôt

Si le dépôt contient un fichier `.env.example`, chaque variable qu'il déclare doit exister dans l'environnement avant la construction. Sinon, le déploiement est refusé avec `variables_requises_manquantes`, et le rapport en donne la liste. Une variable que les commentaires du fichier disent facultative (« optional », « facultatif », « laisser vide »…), ou qui y porte une valeur d'exemple sans avoir un nom de secret, produit seulement un avertissement au journal de construction.

## Depuis la console

Ouvrez **Variables** dans le menu du projet. Les onglets du haut choisissent l'environnement ; l'inventaire montre le nom, la sensibilité, l'origine, la révision et la date de chaque variable, jamais sa valeur.

1. Dans le panneau **Ajouter une variable**, saisissez le nom et la valeur, choisissez **Secret** ou **Visible**.
2. Cochez un ou plusieurs environnements : une écriture part vers chacun.
3. Cliquez sur **Enregistrer**. Un bandeau confirme et propose **Défaire** pendant 5 minutes.

**Modifier** relit la valeur d'une variable visible avant de la remplacer. **Remplacer** sur un secret ouvre un champ vide : l'ancienne valeur ne se montre pas. **Remplacer ici** sur une variable héritée crée une variable propre qui la masque. La corbeille supprime une variable propre ; la version en ligne la garde jusqu'au prochain déploiement.

### Importer un fichier .env

**Importer un .env** ouvre une fenêtre où coller le contenu, ou choisir un fichier ; vous pouvez aussi glisser le fichier sur la page. Le fichier est lu dans le navigateur, son contenu n'est pas affiché, et chaque variable part ensuite par une écriture séparée.

- Une ligne vide ou commençant par `#` est ignorée, `export ` en tête est toléré.
- Entre guillemets doubles, `\n`, `\t`, `\"` et `\\` sont interprétés, et la valeur peut courir sur plusieurs lignes, ce qui permet de coller une clé PEM. Entre guillemets simples, la valeur est littérale.
- Une clé définie deux fois garde la dernière valeur, avec un avertissement.
- `${AUTRE}` n'est pas remplacé : la valeur part telle quelle, avec un avertissement.
- Un fichier de plus de 1 Mo n'est pas lu.

Avant l'envoi, la fenêtre dit ce qui arrivera à chaque variable (ajoutée, remplace la valeur actuelle, masquera celle héritée) et vous laisse cocher **Secret** ligne par ligne. Une écriture refusée n'arrête pas les autres. **Défaire l'import** reprend toutes les écritures pendant 5 minutes.

## Écrire en production, écrire ailleurs

La production a ses propres opérations, distinctes de celles des autres environnements, avec un rang plus élevé.

| Geste | Hors production | Production | Rang minimal |
| --- | --- | --- | --- |
| Lister les noms, sans valeur | `env_list` | `env_list` | Développeur |
| Lire les valeurs visibles | `env_pull_nonproduction` | `env_pull_production` | Développeur / Mainteneur |
| Écrire | `env_write_nonproduction` | `env_write_production` | Développeur / Mainteneur |
| Supprimer | `env_delete_nonproduction` | `env_delete_production` | Développeur / Mainteneur |

Une opération hors production appelée sur la production est refusée (`production_environment` ou `wrong_operation`), et le message nomme l'opération à employer. Les opérations de production ne prennent pas d'identifiant d'environnement : il n'y en a qu'une par projet.

Une écriture ou une suppression rend un `undoToken` : l'outil `action_undo` la défait pendant cinq minutes, une seule fois, pour le même compte. Un compte de service ne peut ni écrire ni supprimer une variable.

## Par un agent

Les outils de variables sont marqués destructifs : votre client MCP vous demande votre accord avant chaque écriture ou suppression. Un agent ne reçoit jamais la valeur d'un secret.

1. `environment_list` rend les environnements et leurs identifiants.
2. `env_list` rend l'inventaire d'un environnement, avec les compteurs à confronter aux plafonds.
3. `env_write_nonproduction` ou `env_write_production` écrit la variable.

```json
{
  "projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "environmentId": "env_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "key": "NEXT_PUBLIC_API_URL",
  "value": "https://api.apercu.exemple.fr",
  "sensitive": false,
  "idempotencyKey": "variable-api-apercu-2026-09-14"
}
```

`env_pull_nonproduction` et `env_pull_production` rendent les valeurs visibles. Chaque valeur arrive enveloppée, marquée comme donnée non fiable, et les variables sensibles sont nommées dans `clesOmises` plutôt que passées sous silence : un appelant sait ainsi qu'elles existent et ne les réécrit pas par erreur.

```json
{
  "variables": {
    "NEXT_PUBLIC_API_URL": {
      "untrusted": true,
      "source": "variable-d-environnement",
      "content": "https://api.apercu.exemple.fr"
    }
  },
  "clesOmises": ["PAIEMENT_CLE_SECRETE"]
}
```

## Par la ligne de commande

```sh
bastide environment list --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567
bastide env list --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 --environment-id env_01JQ8ZK4M7NP2RSTVWXYZ34567
bastide env write production --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 --key PAIEMENT_CLE_SECRETE --value '<clé>'
bastide env pull nonproduction --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 --environment-id env_01JQ8ZK4M7NP2RSTVWXYZ34567
```

`env pull` affiche les valeurs visibles ; il n'écrit pas de fichier. Les écritures et suppressions demandent une confirmation, sauf avec `--yes`. Dans un répertoire lié par `bastide link`, `--project-id` peut être omis.

`bastide doctor` compare les noms des fichiers `.env` de votre poste à ceux de l'environnement déployé, sans jamais lire une valeur, et propose la commande qui rapproche les deux côtés.

> **Conseil.** Une valeur passée par `--value` reste dans l'historique de votre terminal. Pour un secret, préférez la console, ou effacez la ligne de l'historique après coup.

## Par l'API

```sh
curl -X PUT https://api.bastide.app/v1/projects/prj_01JQ8ZK4M7NP2RSTVWXYZ34567/env/production \
  -H "Authorization: Bearer <votre-jeton>" \
  -H "Content-Type: application/json" \
  -d '{"key": "PAIEMENT_CLE_SECRETE", "value": "<clé>", "idempotencyKey": "secret-paiement-2026-09-14"}'
```

Les autres routes sont `GET /v1/projects/{projectId}/env` (inventaire), `GET …/env/pull` et `…/env/pull/production` (valeurs visibles), `PUT` et `DELETE …/env` (hors production) et `…/env/production`. Voir la [référence de l'API](../reference/api.md).

## Limites

Elles sont les mêmes à tous les paliers.

| Limite | Valeur |
| --- | --- |
| Variables par environnement | 1 000 |
| Taille cumulée des valeurs d'un environnement | 256 Ko (262 144 octets) |
| Taille d'une valeur | 64 Ko (65 536 octets) |
| Longueur d'un nom | 64 caractères |
| Délai pour défaire une écriture | 5 minutes |

## Erreurs fréquentes

| Code | Cause | Remède |
| --- | --- | --- |
| `production_environment`, `wrong_operation` | Une opération hors production visait la production. | Employer `env_write_production`, `env_pull_production` ou `env_delete_production`, au rang Mainteneur. |
| `secret_never_read` | La lecture nommait une variable sensible. | Remplacer le secret par une nouvelle valeur ; il ne se relit pas. |
| `quota_exceeded` | 1 000 variables ou 256 Ko atteints. | Supprimer des variables inutiles, ou regrouper des valeurs. |
| `invalid_request` | Nom hors grammaire, nom refusé (`LD_PRELOAD`…) ou valeur de plus de 64 Ko. | Corriger le nom ou la valeur ; le message nomme la règle. |
| `secret_store_unavailable` | Le magasin de secrets est injoignable. | Réessayer plus tard ; rien n'a été écrit. |
| `variables_requises_manquantes` | Le `.env.example` du dépôt déclare une variable absente. | Écrire la variable, ou la marquer facultative dans `.env.example`, puis redéployer. |

## Voir aussi

- [Prévisualisations](previews.md)
- [Déployer](deploy.md)
- [Restaurer](restore.md)
- [Sécurité des agents](agent-safety.md)
- [Comptes de service](service-accounts.md)
- [env.write.production](../reference/operations/env.write.production.md), [env.pull.nonproduction](../reference/operations/env.pull.nonproduction.md), [secret.reveal](../reference/operations/secret.reveal.md)
