Cloud Functions for Firebase en 2026 : le guide complet du serverless Google
Les Cloud Functions Firebase permettent d'exécuter du code backend sans gérer de serveur. En 2026, la 2ème génération basée sur Cloud Run change tout : plus de puissance, meilleure scalabilité, cold start réduit, tarification revue.

Si tu construis une app avec Firebase et que tu as besoin d'exécuter du code côté serveur — envoyer un email, appeler une API de paiement, traiter une image, générer un PDF, orchestrer un agent IA — tu vas croiser tôt ou tard les Cloud Functions for Firebase. C'est la brique qui te permet de sortir du strict client/DB et de faire vraiment tourner du backend, sans jamais provisionner un VPS ni configurer un Nginx.
En 2026, cette brique est arrivée à maturité. La 2ème génération basée sur Cloud Run a remplacé l'ancienne architecture, les runtimes récents (Node 22, Python 3.13) sont disponibles, et le modèle de tarification a été revu à la baisse pour la plupart des cas d'usage. Mais il reste des pièges classiques : cold start, coûts qui gonflent, sécurité mal configurée, timeouts inadaptés.
Cet article couvre tout ce qu'il faut savoir pour concevoir, développer, déployer et opérer des Cloud Functions Firebase sereinement en 2026.
Serverless : la promesse et ce qui la rend intéressante
Le principe des Cloud Functions est simple : tu écris une fonction, tu la déploies, et Google Cloud la fait tourner uniquement quand elle est appelée. Pas de serveur qui tourne 24/7 à vide, pas de patch système à gérer, pas d'autoscaling à configurer.
Concrètement, ça veut dire trois choses :
- Tu ne paies que ton usage réel (à l'invocation et à la milliseconde d'exécution)
- Le scaling est automatique — 1 requête ou 10 000 requêtes/seconde, Google gère
- Tu te concentres sur ton code métier, pas sur l'infra
En contrepartie, tu acceptes des contraintes : temps d'exécution limité, environnement éphémère (rien n'est persisté entre deux invocations), latence de "démarrage à froid" quand la fonction n'a pas été appelée depuis un moment.
1ère gen vs 2ème gen : où en est-on en 2026
Firebase Cloud Functions existe en deux générations qui coexistent, mais la 2ème génération est le standard recommandé en 2026 pour tout nouveau projet.
1ère génération : le service historique, basé sur Google Cloud Functions v1. Toujours supportée, mais Google n'y ajoute plus de fonctionnalités. À réserver aux projets legacy.
2ème génération : sortie en 2022, généralisée depuis 2023, elle repose sur Cloud Run sous le capot. Ça change plusieurs choses :
- Concurrence par instance : une seule instance peut traiter plusieurs requêtes en parallèle (jusqu'à 1 000 par défaut), au lieu d'une par invocation
- Timeouts plus longs : jusqu'à 60 minutes pour les triggers HTTP, contre 9 minutes en gen 1
- Plus de mémoire et de CPU : jusqu'à 32 Go de RAM et 8 vCPU
- Support des
minInstances: garder N instances toujours "chaudes" pour éliminer le cold start - Concurrence multi-région : déploiement facile sur plusieurs régions
- Meilleure tarification pour les charges avec du parallélisme
Si tu démarres un projet en 2026, écris directement en 2ème gen. La différence dans le code est minimale mais les gains opérationnels sont énormes.
Les runtimes disponibles en 2026
Voici les runtimes supportés par les Cloud Functions Firebase 2ème gen au moment d'écrire cet article :
Node.js :
- Node.js 20 (LTS)
- Node.js 22 (LTS, recommandé pour les nouveaux projets)
Python :
- Python 3.11
- Python 3.12
- Python 3.13 (recommandé)
Java, Go, .NET, Ruby, PHP sont supportés par Cloud Run functions (le service Google Cloud sous-jacent) mais l'intégration Firebase reste focalisée sur Node et Python.
Structure d'un projet Cloud Functions
Quand tu lances firebase init functions dans ton projet Firebase, la CLI crée un dossier functions/ avec cette structure typique en Node.js :
functions/
├── package.json
├── tsconfig.json (si TypeScript)
├── src/
│ ├── index.ts (point d'entrée)
│ ├── auth.ts (fonctions liées à Auth)
│ ├── payments.ts (webhooks CinetPay, Stripe, Wave...)
│ └── notifications.ts
└── .gitignore
Le package.json déclare le runtime cible :
{
"name": "functions",
"engines": { "node": "22" },
"main": "lib/index.js",
"scripts": {
"build": "tsc",
"deploy": "firebase deploy --only functions",
"serve": "firebase emulators:start --only functions"
},
"dependencies": {
"firebase-admin": "^12.0.0",
"firebase-functions": "^6.0.0"
}
}
Chaque fonction exportée depuis index.ts devient une fonction déployable individuellement.
Les triggers HTTP
Le trigger le plus courant est HTTP. Il permet à ton client (web ou mobile) d'appeler une fonction serveur.
Deux variantes existent :
Callable functions : appelées via le SDK Firebase client. Elles gèrent automatiquement l'auth (le user id est disponible sans configuration), la sérialisation JSON, et l'intégration avec App Check.
import { onCall, HttpsError } from "firebase-functions/v2/https";
import { initializeApp } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";
initializeApp();
export const createOrder = onCall(
{ region: "europe-west1", enforceAppCheck: true },
async (request) => {
if (!request.auth) {
throw new HttpsError("unauthenticated", "Connexion requise");
}
const { items, total } = request.data;
if (!Array.isArray(items) || typeof total !== "number") {
throw new HttpsError("invalid-argument", "Données invalides");
}
const orderRef = await getFirestore().collection("orders").add({
userId: request.auth.uid,
items,
total,
status: "pending",
createdAt: new Date()
});
return { orderId: orderRef.id };
}
);
Côté client (web) :
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const createOrder = httpsCallable(functions, "createOrder");
const result = await createOrder({ items: [...], total: 12500 });
console.log(result.data.orderId);
HTTPS requests bruts : pour recevoir des webhooks externes (paiement, SMS, etc.).
import { onRequest } from "firebase-functions/v2/https";
export const cinetpayWebhook = onRequest(
{ region: "europe-west1", cors: false },
async (req, res) => {
if (req.method !== "POST") {
res.status(405).send("Method Not Allowed");
return;
}
const signature = req.headers["x-cinetpay-signature"];
if (!verifySignature(req.body, signature)) {
res.status(403).send("Invalid signature");
return;
}
await updateOrderFromWebhook(req.body);
res.status(200).send("OK");
}
);
Les triggers événements Firebase et Google Cloud
Les Cloud Functions peuvent aussi réagir à des événements internes à ton projet, sans intervention client.
Firestore trigger : réagit à la création, modification ou suppression d'un document.
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { getMessaging } from "firebase-admin/messaging";
export const notifyOnNewOrder = onDocumentCreated(
"orders/{orderId}",
async (event) => {
const order = event.data?.data();
if (!order) return;
await getMessaging().send({
topic: "admins",
notification: {
title: "Nouvelle commande",
body: `Commande de ${order.total} FCFA`
}
});
}
);
Auth trigger : réagit à la création ou suppression d'un utilisateur (via les Blocking Functions v2, ou via Firestore side-effects).
Storage trigger : réagit à l'upload ou la suppression d'un fichier.
Scheduled trigger : exécution périodique (cron).
import { onSchedule } from "firebase-functions/v2/scheduler";
export const dailyReport = onSchedule(
{ schedule: "every day 07:00", timeZone: "Africa/Abidjan" },
async () => {
await generateAndSendDailyReport();
}
);
Pub/Sub trigger : réagit à un message sur un topic Google Cloud Pub/Sub. Utile pour découpler des services entre eux.
Un exemple Python complet
Si tu préfères Python, voici l'équivalent d'une fonction callable simple qui envoie un OTP par SMS.
from firebase_functions import https_fn, options
from firebase_admin import initialize_app
import random
import string
initialize_app()
@https_fn.on_call(
region="europe-west1",
enforce_app_check=True,
secrets=["TWILIO_TOKEN"]
)
def send_otp(req: https_fn.CallableRequest) -> dict:
if not req.auth:
raise https_fn.HttpsError(
https_fn.FunctionsErrorCode.UNAUTHENTICATED,
"Login required"
)
phone = req.data.get("phone")
if not phone or not phone.startswith("+"):
raise https_fn.HttpsError(
https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
"Invalid phone"
)
otp = "".join(random.choices(string.digits, k=6))
send_via_twilio(phone, f"Ton code: {otp}")
return {"sent": True}
Cold start : ce que c'est, comment le maîtriser
Le cold start est le temps que met une fonction à démarrer quand aucune instance n'est chaude. En 2ème gen, il est généralement compris entre 300 ms et 3 secondes selon la taille du bundle, la mémoire allouée et le runtime.
Pour les endpoints critiques (ex. un login), 3 secondes c'est trop. Voici comment limiter le cold start :
Configurer minInstances : garder N instances toujours prêtes. Elles consomment un peu même à vide, mais le premier appel n'attend plus.
export const login = onCall(
{ minInstances: 2, region: "europe-west1" },
async (request) => { /* ... */ }
);
Réduire la taille du bundle : n'importe pas des dépendances lourdes globalement. Utilise du code splitting.
Augmenter la mémoire : plus de RAM = plus de CPU proportionnel. Une fonction à 256 Mo démarre plus vite qu'une à 128 Mo dans beaucoup de cas.
Éviter les initialisations coûteuses au top-level : lazy-load ce qui n'est pas nécessaire à toutes les requêtes.
Sécurité : App Check, Auth et IAM
Une Cloud Function HTTP est exposée publiquement. Si tu ne la sécurises pas, n'importe qui peut la spammer. Trois couches de sécurité à combiner.
Firebase Auth context : dans une callable function, request.auth te donne l'utilisateur connecté (uid, token). Refuse la requête si request.auth est absent.
App Check : garantit que la requête vient bien de ton app authentique (Android via Play Integrity, iOS via App Attest, Web via reCAPTCHA Enterprise). Active enforceAppCheck: true sur toutes tes callables publiques.
Rôles IAM : les fonctions non publiques (interne à ton backend) peuvent être restreintes via les rôles IAM Google Cloud. Une fonction non-appelable directement par un client aura son rôle roles/run.invoker limité à un service account précis.
Cloud Secret Manager : pour les clés d'API tierces (Stripe, Twilio, OpenAI...), ne les mets jamais en clair dans le code ou dans un .env commité. Utilise secrets :
import { defineSecret } from "firebase-functions/params";
const stripeKey = defineSecret("STRIPE_SECRET_KEY");
export const chargeCustomer = onCall(
{ secrets: [stripeKey], region: "europe-west1" },
async (request) => {
const stripe = new Stripe(stripeKey.value());
// ...
}
);
Tarification 2026 : décomposition et exemples
Les Cloud Functions 2ème gen sont facturées sur trois axes :
Invocations : $0,40 par million d'invocations, après un quota gratuit mensuel de 2 millions.
Compute : facturé à la vCPU-seconde et au GB-seconde de RAM utilisée. Pour un endpoint moyen (0,25 vCPU, 256 Mo, 200 ms d'exécution), on parle de fractions de centimes par milliers d'appels.
Trafic sortant réseau : $0,12 par Go sortant vers Internet, après quotas.
Exemple concret : un webhook CinetPay qui reçoit 10 000 appels/jour avec une exécution moyenne de 300 ms à 256 Mo. Sur un mois :
- 300 000 invocations → largement dans le quota gratuit
- Compute : ~7 500 GB-secondes → quelques dizaines de centimes
- Trafic : quelques Mo → gratuit
Total mensuel : moins de 1 dollar. Le serverless est écrasant en efficacité pour ces charges.
Piège classique : une fonction qui appelle en boucle une API tierce sans limite, ou qui écrit dans Firestore dans un trigger onCreate qui se re-déclenche lui-même. C'est ce qui fait exploser les factures, pas le trafic normal. Configure toujours une alerte budget Google Cloud dès la mise en Blaze.
Émuler en local
Le développement Cloud Functions se fait quasi obligatoirement avec l'Emulator Suite. Sinon, chaque test consomme du quota et prend 1 seconde de plus.
firebase emulators:start --only functions,firestore,auth
Ton code appelle automatiquement les émulateurs si tu configures ton client :
import { connectFunctionsEmulator } from "firebase/functions";
if (location.hostname === "localhost") {
connectFunctionsEmulator(functions, "localhost", 5001);
}
Tu peux même écrire des tests d'intégration Jest ou Vitest qui démarrent l'émulateur, appellent tes fonctions et vérifient l'état Firestore. Indispensable dès qu'une fonction contient une logique métier non triviale.
Debug, logs et observabilité
En production, les logs de tes Cloud Functions sont envoyés dans Google Cloud Logging. Tu les consultes depuis la console Firebase ou depuis console.cloud.google.com.
Bonnes pratiques :
- Utilise
logger.info,logger.warn,logger.errordu packagefirebase-functions/logger - Écris des structured logs (objets JSON) plutôt que du texte brut : plus faciles à filtrer et à corréler
- Ajoute un
traceIdunique à chaque requête pour suivre une exécution de bout en bout - Configure les sourcemaps si tu es en TypeScript pour avoir des stack traces lisibles
import { logger } from "firebase-functions/v2";
logger.info("Order created", { orderId, userId, total });
Déploiement CI/CD via GitHub Actions
Le déploiement manuel via firebase deploy marche, mais dès que tu es plusieurs sur le projet, automatise-le.
Un workflow GitHub Actions minimal :
name: Deploy Functions
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '22' }
- run: cd functions && npm ci && npm run build
- uses: w9jds/firebase-action@master
with:
args: deploy --only functions
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
Utilise un service account dédié avec juste Cloud Functions Admin + Service Account User, pas ton compte perso.
Limites à connaître
Quelques plafonds importants en 2ème gen :
- Timeout HTTP : 60 minutes max (contre 9 min en gen 1)
- Timeout event-driven : 10 minutes max
- Mémoire max : 32 Go
- vCPU max : 8
- Taille max de requête : 32 Mo
- Taille max de réponse HTTP : 32 Mo
- Nombre d'instances max simultanées : configurable via
maxInstances
Régions supportées en 2026 : les grandes régions Google Cloud, dont europe-west1 (Belgique) qui est la région recommandée pour l'Afrique de l'Ouest (latence typique 100-200 ms depuis Abidjan).
Cas d'usage typiques en 2026
Webhooks de paiement (CinetPay, Wave, Stripe, PayDunya) : ta callable reçoit le webhook, vérifie la signature, met à jour Firestore, envoie une notification push.
Traitement d'images : trigger Storage qui redimensionne un upload en 3 tailles (thumbnail, medium, large), avec sharp en Node.
Notifications push : trigger Firestore qui, à chaque création de commande, envoie une notif FCM aux admins.
Génération de PDF : callable qui génère une facture avec pdfkit, la stocke dans Storage, retourne l'URL signée.
Agent IA : callable qui appelle Genkit ou l'API Gemini pour générer une réponse à une question utilisateur, avec logs des traces.
Cron reports : onSchedule quotidien qui agrège les stats de la veille et envoie un email récap au dirigeant.
Migrations de données : callable admin (protégée par rôle custom claim) qui parcourt une collection Firestore et met à jour un champ.
Best practices que je recommande
- Toujours activer
enforceAppChecksur les callables publiques - Toujours configurer une alerte budget Google Cloud à un montant que tu peux te permettre
- Toujours utiliser les émulateurs en dev, jamais taper directement en prod
- Ne pas mettre de secret en dur — utiliser
defineSecret/ Secret Manager - Structurer les logs en JSON pour la corrélation
- Régionaliser vers
europe-west1pour l'Afrique de l'Ouest - Séparer une fonction par domaine métier (payments.ts, orders.ts, notifications.ts) plutôt qu'un
index.tsgéant - Écrire des tests d'intégration contre les émulateurs pour toute logique non triviale
- Configurer
minInstances: 1sur les endpoints critiques latence-sensibles - Monitorer les cold starts et les erreurs dans Cloud Logging avec des alertes
Les Cloud Functions Firebase en 2026 sont un excellent choix quand tu veux un backend serverless mature, bien intégré à l'écosystème Google et facile à opérer. La 2ème gen a effacé la plupart des limites historiques (timeouts courts, concurrence 1, cold start élevé), et la tarification reste très favorable pour les charges classiques d'une app startup. La discipline à avoir : sécuriser dès le départ avec App Check, monitorer les coûts, émuler en local, structurer proprement le code. À ce prix-là, tu obtiens un backend qui tient la comparaison avec des architectures beaucoup plus complexes.