Cache et images
Bastide tient trois mécanismes qui évitent de refaire le même travail : le cache HTTP de l'edge, qui sert une réponse déjà produite sans solliciter votre application ; la transformation d'images, incluse au forfait ; et le cache distant de construction, compatible Turborepo. Cette page dit comment chacun décide, comment le vider et ce qu'il coûte.
Le cache HTTP de l'edge
Le cache de l'edge suit un contrat publié : en lisant les en-têtes de votre réponse, vous savez sans essai si elle sera rangée. Rien n'est rangé par défaut ; c'est votre application qui le demande.
Ce qui se range
Une réponse est rangée quand toutes ces conditions tiennent :
- la requête est un
GETou unHEAD, sans en-têteRange,AuthorizationniUpgrade; - l'en-tête qui gouverne porte une durée explicite, sans
private,no-cachenino-store; - le statut est 200, 301, 302, 307, 308, 404 ou 410 ;
- la réponse ne pose pas de témoin (
Set-Cookie) et ne porte pasVary: *; - elle pèse 20 Mo au plus, et un 200 a un corps.
L'en-tête qui gouverne est le premier présent parmi Glowsoft-CDN-Cache-Control, CDN-Cache-Control et Cache-Control, et lui seul. Glowsoft-CDN-Cache-Control ne parle qu'au cache de la plateforme ; CDN-Cache-Control aussi à un CDN que vous placeriez devant ; Cache-Control s'adresse d'abord au navigateur.
La durée est s-maxage. max-age ne compte que dans un en-tête ciblé (Glowsoft-CDN-Cache-Control ou CDN-Cache-Control), jamais dans Cache-Control, où il reste la durée du navigateur. Elle est bornée à un an. Expires et les durées heuristiques ne sont pas lus.
Cache-Control: public, max-age=60, s-maxage=3600
Cette réponse est gardée une heure par l'edge et une minute par le navigateur.
Ce qu'il faut savoir
- La clé du cache est la méthode, le nom d'hôte, le chemin et la chaîne de requête. Les témoins de la requête n'en font pas partie : une réponse rangeable ne doit pas en dépendre.
- Un
Varyautre que*range une variante par valeur des en-têtes nommés. - Le
Cache-Controlenvoyé par un visiteur ne contourne rien : unno-cachedu navigateur ne force pas l'origine. - Une entrée échue n'est jamais servie :
stale-while-revalidateetstale-if-errorne sont pas encore honorés. - Un
If-None-Matchqui désigne l'entrée rangée reçoit 304, depuis le cache. - Un redéploiement de l'environnement purge tout ce que la version précédente avait rangé.
Glowsoft-CDN-Cache-ControletGlowsoft-Cache-Tagne sont jamais renvoyés au visiteur.
Lire la décision du cache
Chaque réponse porte l'en-tête Cache-Status (RFC 9211) : hit quand elle vient du cache. Quand le cache ne l'a ni lue ni rangée, detail= donne le motif.
| Motif | Cause |
|---|---|
METHODE | Ni GET ni HEAD. |
PLAGE | Un en-tête Range. |
AUTORISATION | Un en-tête Authorization. |
PASSAGE | Un en-tête Upgrade (WebSocket). |
STATUT | Un statut hors de la liste. |
TEMOIN | La réponse pose un témoin. |
VARY-ETOILE | Vary: *. |
PRIVE | private, no-cache ou no-store. |
SANS-DUREE | Aucune durée explicite. |
TROP-GRAND, TROP-GRAND-EN-FLUX | Plus de 20 Mo, annoncés ou découverts en flux. |
CORPS-VIDE | Un 200 sans corps. |
Révoquer par étiquette
Votre application peut étiqueter ses réponses par l'en-tête Glowsoft-Cache-Tag : des étiquettes séparées par des virgules, 256 caractères au plus chacune. Les étiquettes sont rangées par projet et par environnement : aucune ne traverse un autre locataire.
Glowsoft-Cache-Tag: produit:4512, catalogue
Quand le produit 4512 change, révoquez l'étiquette plutôt que tout le cache. Deux modes existent :
- invalidate (recommandé) : l'entrée périmée est servie une dernière fois et revalidée derrière, si bien que le visiteur ne voit pas l'origine ralentir ;
- delete : l'entrée est détruite. Employez-le pour retirer un contenu qui ne doit plus être servi.
La révocation prend effet en région en moins de deux secondes, d'après l'API.
Depuis la console
Ouvrez Domaines, puis la carte Cache de l'edge. Choisissez l'environnement (la production par défaut), saisissez les étiquettes une par ligne, choisissez le mode, puis Purger.
Par la ligne de commande ou l'API
bastide cache tag revoke --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 --tags '["produit:4512","catalogue"]'
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"tags": ["produit:4512", "catalogue"],
"mode": "invalidate",
"idempotencyKey": "purge-produit-4512-2026-10-14"
}
Ce corps part en POST /v1/projects/{projectId}/cache/purge sur https://api.bastide.app. Sans environmentId, la révocation vise la production. Cent étiquettes au plus par appel, sans virgule. Le geste demande le rang Développeur et une personne : il n'est ouvert ni aux agents ni aux comptes de service.
Les transformations d'images
Chaque site sert /_bastide/image, qui redimensionne une image et la convertit en AVIF ou en WebP selon ce que le navigateur accepte. Les images du site lui-même sont toujours admises ; une source distante doit figurer dans la liste du projet. Chaque URL est signée : une URL non signée, mal signée ou dont la source n'est pas admise reçoit 403 avant toute lecture.
Les paramètres
| Paramètre | Sens |
|---|---|
src | Un chemin du site (/images/a.jpg) ou une URL https:// d'une source admise. |
w, h | Largeur et hauteur, de 1 à 8 192 pixels. |
q | Qualité, de 1 à 100 ; 75 par défaut. |
fit | cover (défaut), contain ou fill. |
format | avif, webp ou origin ; à défaut, négocié par l'en-tête Accept. |
s | La signature. Tout autre paramètre est refusé. |
Signer une URL
La signature est un HMAC-SHA256 de la chaîne canonique, encodé en base64url sans remplissage. La chaîne canonique reprend les paramètres présents parmi src, w, h, q, fit et format, dans cet ordre, sous la forme nom=valeur (valeur encodée comme par encodeURIComponent), séparés par &. La clé est celle que rend le réglage des images, en hexadécimal.
import { createHmac } from "node:crypto";
const cle = Buffer.from(process.env.IMAGES_CLE_DE_SIGNATURE, "hex");
export function urlDImage(src, largeur, qualite = 75) {
const p = new URLSearchParams({ src, w: String(largeur), q: String(qualite) });
const canonique = ["src", "w", "h", "q", "fit", "format"]
.filter((n) => p.has(n))
.map((n) => `${n}=${encodeURIComponent(p.get(n))}`)
.join("&");
p.set("s", createHmac("sha256", cle).update(canonique).digest("base64url"));
return `/_bastide/image?${p}`;
}
Régler les sources et la clé
Ouvrez Domaines, puis la carte Images. Elle montre le compteur de transformations du mois, la génération de la clé et la liste des sources distantes admises, une par ligne (50 au plus, en https).
- Enregistrer et montrer la clé règle la liste et affiche la clé de signature. Elle ne se montre qu'à ce moment : posez-la aussitôt en variable secrète de votre application. Voir Environnements et variables.
- Renouveler la clé en tire une nouvelle : toutes les URL signées sous l'ancienne cessent d'être servies.
- Optimiser à l'écriture donne à chaque image déposée au stockage une variante allégée, servie sans transformation à la lecture. Le réglage est éteint à l'origine.
Les mêmes réglages passent par image.configure et se lisent par image.read, par l'API (PUT et GET /v1/projects/{projectId}/images) ou la ligne de commande (bastide image configure, bastide image read). Régler demande le rang Mainteneur ; lire, le rang Lecteur. Aucun outil MCP ne les porte : la clé est un secret, et aucun outil ne rend de secret.
Ce qui est compté
Seule une transformation faite est comptée. Une image reprise du cache de l'edge ne l'est pas, ni une image servie telle quelle : un SVG, un GIF ou un WebP animé, une source de moins de 10 Ko, ou un format que la transformation ne lit pas. Ces images portent l'en-tête X-Image-Diagnostic, qui dit pourquoi.
Une image transformée est gardée 31 jours par l'edge, dans la portée de l'environnement et de sa version : un redéploiement la périme.
| Découverte | Standard | Pro | Souverain | |
|---|---|---|---|---|
| Transformations incluses par mois | 5 000 | 50 000 | 250 000 | 1 000 000 |
Au-delà du volume inclus, l'image est servie telle quelle, sans transformation et sans facturation. Une alerte part à 80 % du volume du mois : l'événement project.images.threshold, vers vos webhooks et vos notifications.
Limites d'une image
| Limite | Valeur |
|---|---|
| Dimensions de la source | 8 192 pixels de côté |
| Poids de la source | 25 Mo |
| Poids de la sortie | 10 Mo |
| Sources distantes par projet | 50 |
Au-delà, la réponse est un 422 qui nomme la limite. Une source illisible donne 502 ; une transformation qui ne répond pas, 503.
Le cache distant de construction
Turborepo peut déposer et relire ses artefacts dans un cache distant tenu par Bastide, par le protocole /v8/artifacts. L'équipe Turborepo est le projet. Pour l'utiliser depuis votre poste ou votre intégration continue :
export TURBO_API=https://api.bastide.app
export TURBO_TEAM=prj_01JQ8ZK4M7NP2RSTVWXYZ34567
export TURBO_TOKEN=<jeton personnel ou de service>
Lire le cache demande le droit de lire le projet ; y déposer, celui de déployer (rang Développeur, portée deploy:write). Les constructions de la plateforme reçoivent leur propre jeton, limité au cache de leur projet et retiré dès la fin de la construction. Un artefact qui contient un secret est refusé, et le refus nomme le fichier. Un artefact de plus de 128 Mo n'est pas mis en cache ; Turborepo continue sans lui.
Rétention et purge
La rétention va de 1 à 30 jours, 7 par défaut ; elle vaut pour les dépôts suivants. La purge prend effet à l'appel : un artefact purgé n'est plus servi.
- Console : Réglages du projet, carte Cache distant Turborepo. La purge y est totale.
- Agent : l'outil
build_cache_manage, qui purge aussi par empreinte Turborepo. - Ligne de commande :
bastide build_cache manage --project-id prj_… --retention-days 14.
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"purge": [],
"idempotencyKey": "purge-cache-distant-2026-10-14"
}
Une liste purge vide vide tout le cache ; une liste d'empreintes (1 000 au plus) ne retire que celles-ci. La réponse dit combien d'artefacts et d'octets ont été purgés, et ce que le cache tient encore.
Erreurs fréquentes
| Symptôme ou code | Cause | Remède |
|---|---|---|
Cache-Status avec detail=SANS-DUREE | Aucune durée pour l'edge. | Ajouter s-maxage à Cache-Control, ou poser Glowsoft-CDN-Cache-Control. |
detail=TEMOIN | La page pose un témoin de session. | Ne pas poser de témoin sur les réponses publiques. |
detail=PRIVE | private ou no-store dans l'en-tête qui gouverne. | Retirer la directive, ou cibler l'edge par Glowsoft-CDN-Cache-Control. |
| Une page modifiée reste ancienne | Elle est encore dans sa durée de cache. | Révoquer son étiquette, ou redéployer. |
403 sur /_bastide/image | Signature fausse, paramètre non signé, ou source hors de la liste. | Vérifier la chaîne canonique et la clé ; ajouter la source. |
| Images servies sans transformation | Plafond du mois atteint, ou image exemptée. | Lire X-Image-Diagnostic ; changer de palier si le plafond est en cause. |
images_non_reglees | La transformation d'images n'est pas en service sur cette installation. | Contacter le support. |
valeur_rendue_une_fois | Rejeu d'un réglage qui a déjà rendu sa clé. | Régler de nouveau pour obtenir la clé ; elle n'est pas gardée. |