AWS Lambda tourne toujours sur x86 ou ARM Graviton en production, mais le catalogue de runtimes vient de bouger : depuis le 15 août 2026, AWS propose Node.js 26 et Python 3.15 en préversion publique, pendant que Node.js 18 et Python 3.8 sont désormais bloqués à la création et à la mise à jour de fonctions. Si votre stack serverless n’a pas été revue depuis un moment, ce tutoriel vous remet à niveau : on construit, on sécurise et on déploie une fonction Lambda de production en partant d’une page blanche, avec API Gateway, IAM en moindre privilège et une vraie stratégie de coûts.

Le format est volontairement pratique. Chaque étape contient une commande à copier, un résultat attendu et, quand c’est utile, le piège qui fait perdre une heure de débogage. À la fin, vous aurez une API HTTP fonctionnelle, protégée, journalisée et déployée avec l’AWS SAM CLI, prête à passer en CI/CD.

Pourquoi AWS Lambda reste pertinent en 2026

Le calcul serverless n’a pas disparu au profit des edge functions, il s’est simplement spécialisé. Cloudflare Workers domine sur la latence pure grâce à ses isolates V8 (moins de 5 ms de cold start selon un benchmark toolchew.com de mai 2026), mais Lambda garde l’avantage dès qu’il faut toucher à VPC, RDS, EFS, Step Functions ou à l’écosystème IAM complet d’AWS. Ce n’est pas un hasard si la majorité des architectures backend d’entreprise en Europe restent construites autour de Lambda plutôt que d’isolates edge.

Le même benchmark toolchew.com donne un cold start médian de 200 à 350 ms pour Node.js 20 sur Lambda, avec un p99 grimpant à 1,2-2,8 secondes. En face, un rapport de tech-insider.org publié fin mai 2026 mesure un p95 sous 5 ms sur Cloudflare Workers après six semaines de charge en production, soit un écart d’environ 240x sur ce cas précis. C’est un chiffre qui compte pour un webhook ou une authentification en façade, beaucoup moins pour un traitement backend asynchrone où quelques centaines de millisecondes ne changent rien.

Le choix ne se résume donc pas à « le plus rapide gagne ». Il dépend du couplage avec le reste de votre stack cloud. Si vous êtes déjà chez AWS avec DynamoDB, S3 et Cognito, ajouter Lambda coûte une fraction de l’effort qu’exigerait une migration vers un runtime edge distinct.

Prérequis : ce qu’il faut avant de commencer

Installez ces outils avant de démarrer. Les versions indiquées sont celles à jour au 26 août 2026, vérifiez toujours la dernière version stable avant d’installer.

  • Un compte AWS actif avec accès à la console IAM (le tier gratuit couvre largement ce tutoriel)
  • AWS CLI v2 (dernière version stable) configuré avec un profil aws configure
  • AWS SAM CLI (dernière version stable) pour construire et déployer localement
  • Node.js 22.x LTS (runtime stable recommandé par AWS ; Node.js 26 existe en préversion mais évitez-le en production pour l’instant)
  • Docker Desktop ou Docker Engine, utilisé par SAM pour émuler l’environnement Lambda en local
  • Un éditeur de code (VS Code avec l’extension AWS Toolkit simplifie le débogage)
  • curl ou Postman pour tester l’API une fois déployée

Comptez environ 60 minutes pour dérouler l’ensemble du tutoriel, tests inclus. Aucune carte bancaire n’est débitée si vous restez dans les limites du tier gratuit Lambda et API Gateway décrites plus bas.

Étape 1 : initialiser le projet avec AWS SAM

AWS SAM (Serverless Application Model) génère un squelette de projet complet : code de la fonction, définition d’infrastructure et scripts de test. C’est l’approche recommandée par la documentation officielle plutôt que de tout écrire à la main dans la console.

sam init --runtime nodejs22.x --name lambda-api-tutoriel --app-template hello-world --package-type Zip

Répondez « N » à la question sur X-Ray si vous voulez garder ce tutoriel simple (nous l’activerons manuellement plus loin). SAM crée un dossier lambda-api-tutoriel/ avec un fichier template.yaml, un dossier hello-world/ contenant le code, et un dossier events/ pour les payloads de test.

Résultat attendu : la commande affiche « Project generated successfully » suivi de la structure de fichiers créée. Si vous obtenez une erreur « command not found », c’est que SAM CLI n’est pas dans votre PATH, une erreur fréquente sur macOS après une installation via pkg plutôt que Homebrew.

Étape 2 : écrire une fonction Lambda propre en Node.js

Remplacez le contenu de hello-world/app.mjs par une fonction qui respecte les principes officiels de conception d’applications Lambda. La documentation AWS est explicite sur ce point : les fonctions doivent rester sans état et minimiser le couplage avec des ressources externes non gérées.

export const handler = async (event) => {
  try {
    const body = event.body ? JSON.parse(event.body) : {};
    const nom = body.nom || "visiteur";

    const reponse = {
      message: `Bonjour ${nom}, requête traitée avec succès`,
      horodatage: new Date().toISOString(),
      requestId: event.requestContext?.requestId ?? "local-test"
    };

    return {
      statusCode: 200,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(reponse)
    };
  } catch (erreur) {
    console.error("Erreur de traitement:", erreur);
    return {
      statusCode: 400,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ erreur: "Corps de requête invalide" })
    };
  }
};

Trois détails comptent ici. D’abord, le try/catch évite qu’une erreur de parsing JSON ne fasse planter la fonction avec une trace brute exposée au client. Ensuite, console.error alimente automatiquement CloudWatch Logs sans configuration supplémentaire. Enfin, la fonction ne garde aucun état entre deux invocations, ce qui permet à Lambda de la faire tourner en parallèle sur autant d’environnements d’exécution que nécessaire.

Étape 3 : définir l’infrastructure dans template.yaml

Le fichier template.yaml décrit la fonction, son déclencheur API Gateway et ses permissions. Voici une version resserrée, sans les extras générés par défaut.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: API Lambda de tutoriel - shattered.io

Globals:
  Function:
    Timeout: 10
    MemorySize: 256
    Architectures:
      - arm64
    Runtime: nodejs22.x
    Tracing: Active

Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.handler
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /bonjour
            Method: post

Outputs:
  ApiEndpoint:
    Description: URL de l'API déployée
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/bonjour"

Le choix Architectures: arm64 n’est pas cosmétique. Les instances Graviton restent l’option la moins chère par milliseconde d’exécution sur Lambda, et la plupart des runtimes managés (Node.js, Python) fonctionnent nativement dessus sans changement de code. C’est le premier réglage à faire si le coût est un sujet.

Étape 4 : tester la fonction en local avant tout déploiement

SAM peut émuler API Gateway et Lambda en local via Docker, ce qui évite de déployer à chaque itération.

sam build
sam local start-api --port 3000

# Dans un second terminal
curl -X POST http://localhost:3000/bonjour \
  -H "Content-Type: application/json" \
  -d '{"nom": "Claire"}'

Résultat attendu :

{"message":"Bonjour Claire, requête traitée avec succès","horodatage":"2026-08-26T09:14:02.331Z","requestId":"local-test"}

Si la commande sam local start-api échoue avec une erreur de connexion au démon Docker, vérifiez que Docker Desktop est bien lancé. C’est l’erreur la plus fréquente à cette étape, en particulier sur les machines qui ont mis Docker en veille automatique.

Étape 5 : appliquer le principe de moindre privilège avec IAM

Le rôle d’exécution généré par défaut par SAM est correct pour un test, mais trop permissif dès que la fonction touche à d’autres services. La documentation officielle IAM recommande d’attribuer un rôle distinct par fonction plutôt qu’un rôle partagé entre plusieurs Lambdas.

Ajoutez une politique dédiée dans template.yaml si votre fonction a besoin d’écrire dans une table DynamoDB, par exemple :

  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.handler
      Policies:
        - DynamoDBWritePolicy:
            TableName: !Ref RequetesTable
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /bonjour
            Method: post

Évitez absolument les politiques du type "Action": "dynamodb:*" avec "Resource": "*". SAM propose des politiques managées granulaires (DynamoDBReadPolicy, S3WritePolicy, SecretsManagerReadPolicy, etc.) qui limitent l’action et la ressource en une seule ligne. C’est la différence entre une fonction compromise qui ne peut lire qu’une table précise, et une fonction compromise qui peut vider tout le compte.

Étape 6 : chiffrer les variables sensibles avec KMS

Ne mettez jamais une clé d’API ou un secret de base de données en clair dans les variables d’environnement du template.yaml. Passez par AWS Secrets Manager, avec un accès IAM restreint à la fonction qui en a réellement besoin.

aws secretsmanager create-secret \
  --name lambda-tutoriel/db-password \
  --secret-string '{"password":"VOTRE_MOT_DE_PASSE_ICI"}'

Puis, dans le code de la fonction, récupérez le secret à l’exécution plutôt qu’au build :

import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";

const client = new SecretsManagerClient({});
let secretCache = null;

async function obtenirSecret() {
  if (secretCache) return secretCache;
  const commande = new GetSecretValueCommand({ SecretId: "lambda-tutoriel/db-password" });
  const reponse = await client.send(commande);
  secretCache = JSON.parse(reponse.SecretString);
  return secretCache;
}

La mise en cache dans une variable de module (secretCache) évite d’appeler Secrets Manager à chaque invocation : le conteneur d’exécution Lambda est réutilisé entre appels « chauds », donc la variable persiste et vous économisez des appels API facturés.

Étape 7 : déployer avec sam deploy

sam deploy --guided

Répondez aux questions interactives (nom de la stack, région, confirmation des changements IAM). SAM crée un fichier samconfig.toml qui mémorise vos réponses pour les déploiements suivants, ce qui permet ensuite de lancer simplement sam deploy sans le flag --guided.

Résultat attendu : après quelques minutes, la sortie affiche le bloc CloudFormation outputs avec l’URL de votre API. Testez-la immédiatement :

curl -X POST https://VOTRE-ID.execute-api.eu-west-3.amazonaws.com/Prod/bonjour \
  -H "Content-Type: application/json" \
  -d '{"nom": "Production"}'

Étape 8 : activer le monitoring avec CloudWatch et X-Ray

Le champ Tracing: Active déjà présent dans le template.yaml active AWS X-Ray, qui trace chaque requête à travers API Gateway et Lambda. Ouvrez la console X-Ray après quelques appels pour visualiser la latence réelle décomposée par segment (temps d’init, temps d’exécution, appels réseau sortants).

Ajoutez une alarme CloudWatch sur le taux d’erreurs pour être notifié avant que les utilisateurs ne se plaignent :

aws cloudwatch put-metric-alarm \
  --alarm-name lambda-tutoriel-erreurs \
  --metric-name Errors \
  --namespace AWS/Lambda \
  --statistic Sum \
  --period 300 \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 1 \
  --dimensions Name=FunctionName,Value=lambda-api-tutoriel-ApiFunction

Les logs bruts de console.log suffisent pour un test rapide, mais deviennent illisibles dès que le trafic augmente. Structurez-les en JSON dès le départ pour pouvoir les filtrer avec CloudWatch Logs Insights sans réécrire le code plus tard.

function logStructure(niveau, message, contexte = {}) {
  console.log(JSON.stringify({
    niveau,
    message,
    timestamp: new Date().toISOString(),
    ...contexte
  }));
}

// Dans le handler :
logStructure("info", "requête reçue", { requestId: event.requestContext?.requestId });

Une fois ce format en place, une requête CloudWatch Logs Insights comme fields @timestamp, message | filter niveau = "error" retrouve instantanément toutes les erreurs sur une période donnée, sans grep manuel sur des lignes de texte libre. C’est un gain de temps réel le jour où il faut diagnostiquer un incident en production à 2h du matin.

Étape 9 : gérer la concurrence et éviter le throttling

Par défaut, un compte AWS partage un quota de concurrence de 1 000 exécutions simultanées entre toutes ses fonctions Lambda d’une même région. Si un pic de trafic sur une fonction consomme tout le quota, les autres fonctions du compte commencent à être throttlées (erreur 429). Réservez de la concurrence pour vos fonctions critiques :

  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      ReservedConcurrentExecutions: 20
      CodeUri: hello-world/
      Handler: app.handler

Pour les APIs qui ne tolèrent pas de cold start (paiement, authentification), la concurrence provisionnée maintient des environnements d’exécution déjà « chauds ». C’est un coût fixe supplémentaire, donc réservez-la uniquement aux endpoints où la latence a un impact business mesurable.

Étape 10 : réduire le cold start en pratique

Le cold start dépend surtout de la taille du package déployé. Un benchmark publié en février 2026 par InventiveHQ montre qu’une fonction Node.js minimale démarre en 80-150 ms, contre 150-300 ms avec un package volumineux incluant des dépendances non utilisées. Trois leviers concrets :

  • Passez en revue votre package.json et retirez tout ce qui n’est pas strictement nécessaire à l’exécution (les dépendances de dev ne doivent jamais être packagées)
  • Utilisez des Lambda Layers pour mutualiser les dépendances lourdes (SDK, ORM) entre plusieurs fonctions plutôt que de les dupliquer dans chaque package
  • Évitez de mettre une fonction Lambda dans un VPC si elle n’a pas besoin d’accéder à une ressource privée : la documentation AWS confirme que le rattachement VPC ajoute une latence d’initialisation supplémentaire par rapport à une fonction hors VPC

Étape 11 : automatiser le déploiement avec une CI/CD

Une fois la fonction stable, sortez du déploiement manuel. Voici un exemple minimal de workflow GitHub Actions qui build et déploie à chaque push sur main :

name: Deploiement Lambda
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/setup-sam@v2
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploiement-lambda-ci
          aws-region: eu-west-3
      - run: sam build
      - run: sam deploy --no-confirm-changeset --no-fail-on-empty-changeset

Utilisez un rôle IAM assumé via OpenID Connect (role-to-assume) plutôt que des clés d’accès statiques stockées en secret GitHub. C’est la méthode recommandée par AWS pour la CI/CD depuis plusieurs années, et elle évite qu’une clé d’accès à durée de vie illimitée ne fuite dans les logs d’un pipeline.

Étape 12 : ajouter des tests automatisés

import { handler } from "../app.mjs";
import assert from "node:assert";
import test from "node:test";

test("répond 200 avec un nom valide", async () => {
  const event = { body: JSON.stringify({ nom: "Test" }) };
  const resultat = await handler(event);
  assert.strictEqual(resultat.statusCode, 200);
  const corps = JSON.parse(resultat.body);
  assert.ok(corps.message.includes("Test"));
});

test("répond 400 avec un corps invalide", async () => {
  const event = { body: "{invalide" };
  const resultat = await handler(event);
  assert.strictEqual(resultat.statusCode, 400);
});

Lancez ces tests avec node --test avant chaque déploiement, en local ou dans la CI. Un handler testé unitairement révèle immédiatement les régressions de contrat d’API, bien avant qu’un client ne les découvre.

Comparatif des plateformes serverless en 2026

Voici les chiffres de cold start les plus cités dans les benchmarks 2026, à prendre comme ordre de grandeur plutôt que comme vérité absolue : les résultats varient selon la charge utile, la région et la taille du package.

PlateformeCold start (fonction minimale)Cold start (avec dépendances)Modèle d’exécution
Cloudflare Workers< 1 ms< 5 msIsolates V8, edge
AWS Lambda (Node.js)80-150 ms150-300 msMicro-VM Firecracker, régional
AWS Lambda (Python)100-200 ms200-500 msMicro-VM Firecracker, régional
Google Cloud Functions 2e gen200-500 ms500 ms-1,5 sCloud Run sous-jacent
Azure Functions (Consumption)500 ms-2 s1-3 sApp Service sous-jacent
AWS Lambda (Java)800 ms-3 s2-5 sJVM, atténué par SnapStart

Source des ordres de grandeur : comparatif InventiveHQ, février 2026.

État des runtimes Lambda au 26 août 2026

RuntimeIdentifiantStatut au 26/08/2026
Node.js 26nodejs26.xPréversion publique depuis le 15/08/2026
Node.js 24nodejs24.xSupporté, EOL prévue avril 2028
Node.js 22nodejs22.xSupporté, EOL prévue avril 2027
Node.js 18nodejs18.xDéprécié, bloqué en création et mise à jour
Python 3.15python3.15Préversion publique depuis le 15/08/2026
Python 3.13 / 3.14python3.13 / python3.14Supportés, recommandés en production
Python 3.8python3.8Déprécié, bloqué aux mises à jour

Source : documentation officielle AWS Lambda Runtimes. Si votre fonction tourne encore sur Node.js 18 ou Python 3.8, planifiez la migration maintenant : une fonction bloquée aux mises à jour ne peut plus recevoir de correctifs de sécurité tant que le runtime n’est pas changé.

5 erreurs fréquentes à éviter

  • Rôle IAM trop large : attribuer AdministratorAccess ou une politique avec des wildcards à une fonction Lambda parce que « ça marche plus vite ». En cas de compromission du code (dépendance vulnérable, injection), l’attaquant hérite de ce rôle.
  • Invocation récursive non contrôlée : une fonction qui s’invoque elle-même, ou déclenche un processus qui la réinvoque, sans condition de sortie. La documentation AWS le signale explicitement comme un piège classique qui peut générer une facture inattendue avant d’être repéré.
  • Secrets en variables d’environnement en clair : un mot de passe de base de données visible dans la console IAM par n’importe qui ayant accès en lecture à la fonction, au lieu de passer par Secrets Manager avec chiffrement KMS.
  • Package trop lourd : embarquer le SDK AWS complet ou des dépendances de développement dans le ZIP de déploiement, ce qui alourdit le cold start inutilement.
  • Pas de gestion des erreurs granulaire : laisser une exception non interceptée remonter telle quelle au client, exposant parfois la stack trace ou des détails d’implémentation interne.

Sécuriser l’API avec API Gateway

Une fonction Lambda bien codée ne suffit pas si l’API Gateway devant elle est ouverte à tout le monde sans limite. Ajoutez a minima un plan d’utilisation avec throttling pour éviter qu’un client mal configuré (ou malveillant) ne sature vos quotas de concurrence.

aws apigateway create-usage-plan \
  --name plan-tutoriel \
  --throttle burstLimit=50,rateLimit=20 \
  --quota limit=10000,period=MONTH

Pour une API publique, ajoutez ensuite un WAF devant API Gateway afin de filtrer les patterns d’attaque connus (injection SQL, XSS, bots) avant même que la requête n’atteigne Lambda. Le OWASP Serverless Top 10 classe justement l’absence de contrôle en périphérie parmi les risques récurrents des architectures serverless mal configurées.

Pensez aussi à verrouiller les en-têtes CORS si l’API est appelée depuis un navigateur. Un Access-Control-Allow-Origin: * laissé par défaut autorise n’importe quel site tiers à interroger votre API depuis le navigateur d’un utilisateur connecté. Remplacez-le par la liste explicite des domaines autorisés dans la configuration API Gateway, et validez systématiquement l’origine côté fonction si vous gérez le CORS manuellement plutôt que via API Gateway.

Maîtriser les coûts : tier gratuit et au-delà

Lambda facture au nombre d’invocations et au temps de calcul consommé (en Go-secondes), avec un tier gratuit permanent qui couvre largement un projet de test ou une petite API à faible trafic. Vérifiez les seuils exacts et les tarifs par région sur la page officielle de tarification Lambda, car ils varient selon la région et évoluent avec le temps.

Trois réglages réduisent la facture sans toucher au code :

  • Basculer sur l’architecture arm64 (Graviton) quand le runtime le permet, généralement moins cher à consommation équivalente que x86_64
  • Ajuster finement la mémoire allouée avec un outil de type Lambda Power Tuning plutôt que de fixer une valeur arbitraire : plus de mémoire accélère parfois l’exécution au point de réduire le coût total malgré un tarif horaire plus élevé
  • Fixer un timeout réaliste (10 secondes suffit pour la plupart des APIs synchrones) pour qu’une fonction bloquée ne consomme pas inutilement des Go-secondes avant d’échouer

Migrer une fonction existante depuis Node.js 18 ou Python 3.8

Si vous gérez déjà des fonctions en production sur un runtime déprécié, la migration n’est pas optionnelle : une fonction bloquée aux mises à jour ne peut plus recevoir de correctifs de sécurité, et AWS continue de resserrer le calendrier de dépréciation chaque année. Voici la marche à suivre sans interrompre le service.

Commencez par dupliquer la fonction sous un nouveau nom plutôt que de modifier la fonction en place. Cela permet de tester le nouveau runtime en parallèle du trafic réel sans risque.

aws lambda get-function --function-name ancienne-fonction \
  --query 'Code.Location' --output text

# Modifiez le runtime dans template.yaml, puis :
sam build
sam deploy --stack-name nouvelle-fonction-test

Les changements de comportement les plus fréquents entre Node.js 18 et Node.js 22 concernent le support natif des modules ES (préférez .mjs à .js avec CommonJS), la version du SDK AWS embarqué par défaut (SDK v3 uniquement, le v2 n’est plus inclus nativement) et le comportement de certaines API de streaming. Passez vos tests unitaires sur le nouveau runtime avant tout basculement de trafic, puis utilisez un alias Lambda avec un poids de trafic progressif (10 %, puis 50 %, puis 100 %) pour limiter le risque si un comportement inattendu apparaît en production.

Pour Python, la migration de 3.8 vers 3.13 ou 3.14 implique généralement de revérifier les dépendances qui s’appuient sur des extensions C compilées (comme certaines versions de cryptography ou numpy), car elles doivent être reconstruites pour la nouvelle version de l’interpréteur. Reconstruisez toujours vos Lambda Layers Python après un changement de version majeure plutôt que de réutiliser un layer compilé pour l’ancien runtime.

Conseils avancés pour la production

Une fois l’API stable, quelques ajustements séparent un prototype d’un service réellement prêt pour la charge réelle.

Isolez chaque environnement (dev, staging, prod) dans une stack CloudFormation distincte plutôt que de partager une même fonction avec des variables d’environnement qui changent selon le contexte. Cela évite qu’un déploiement de test n’écrase accidentellement la configuration de production. Mettez en place des alias Lambda avec des poids de trafic pour déployer en canari : dirigez d’abord 5 % du trafic vers la nouvelle version, surveillez le taux d’erreur pendant quelques minutes, puis montez progressivement vers 100 %.

Pour les workloads qui orchestrent plusieurs étapes longues, AWS documente désormais des durable functions sur Lambda, disponibles sur Node.js 22/24 et Python 3.13/3.14, une alternative à Step Functions pour certains scénarios d’orchestration directement dans le code de la fonction plutôt que dans une machine à états séparée.

Alternative : déployer Lambda avec une image de conteneur

Ce tutoriel utilise un paquet ZIP, l’option la plus simple pour démarrer. Mais Lambda accepte aussi les images de conteneur (jusqu’à 10 Go), une option pertinente si votre équipe possède déjà des pipelines Docker ou si la fonction embarque des dépendances système lourdes (bibliothèques natives, modèles de machine learning, binaires compilés) difficiles à packager en ZIP avec des Layers.

FROM public.ecr.aws/lambda/nodejs:22

COPY app.mjs package.json ${LAMBDA_TASK_ROOT}
RUN npm install --production

CMD ["app.handler"]
aws ecr create-repository --repository-name lambda-api-tutoriel

docker build -t lambda-api-tutoriel .
docker tag lambda-api-tutoriel:latest VOTRE_COMPTE.dkr.ecr.eu-west-3.amazonaws.com/lambda-api-tutoriel:latest

aws ecr get-login-password --region eu-west-3 | \
  docker login --username AWS --password-stdin VOTRE_COMPTE.dkr.ecr.eu-west-3.amazonaws.com

docker push VOTRE_COMPTE.dkr.ecr.eu-west-3.amazonaws.com/lambda-api-tutoriel:latest

Le compromis à connaître : une image de conteneur démarre en général plus lentement à froid qu’un ZIP léger, parce que Lambda doit charger une couche supplémentaire d’abstraction avant d’exécuter le handler. Réservez cette approche aux cas où la complexité des dépendances justifie le coût en latence, et gardez le ZIP pour les fonctions HTTP simples comme celle construite dans ce tutoriel. Dans les deux cas, le rôle IAM, la politique de concurrence et la configuration API Gateway restent identiques : seul le mode de packaging du code change.

Le projet complet, étape par étape

Récapitulatif de l’architecture finale construite dans ce tutoriel. Un client envoie une requête POST à API Gateway, protégée par un plan d’utilisation avec throttling. API Gateway déclenche la fonction Lambda, qui lit un secret dans Secrets Manager (mis en cache entre invocations), traite la requête et répond en JSON. X-Ray trace chaque segment, CloudWatch déclenche une alarme si le taux d’erreur dépasse le seuil, et le tout est déployé automatiquement via GitHub Actions à chaque push sur la branche principale.

Structure de fichiers finale :

lambda-api-tutoriel/
├── template.yaml
├── samconfig.toml
├── hello-world/
│   ├── app.mjs
│   ├── package.json
│   └── tests/
│       └── unit.test.mjs
├── events/
│   └── event.json
└── .github/
    └── workflows/
        └── deploy.yml

Organiser plusieurs fonctions Lambda dans un même projet

Un seul template.yaml avec une fonction convient pour ce tutoriel, mais une API réelle compte vite dix, vingt ou cinquante fonctions. La tentation est de tout entasser dans un template unique, ce qui fonctionne au début puis devient ingérable : chaque déploiement redéploie potentiellement l’ensemble des ressources, et un changement de stack CloudFormation ralentit à mesure que le nombre de ressources augmente.

Deux approches se dégagent en pratique. La première regroupe les fonctions par domaine métier (facturation, authentification, notifications) dans des stacks distinctes, chacune avec son propre template.yaml et son propre pipeline de déploiement. C’est l’option la plus simple à maintenir pour une équipe de taille moyenne, parce qu’une modification sur le domaine facturation ne redéploie jamais le domaine notifications.

La seconde utilise un monorepo avec un dossier par fonction, chacun contenant son propre code et ses propres dépendances, mais orchestré par un outil comme AWS CDK ou un système de build partagé qui ne déploie que les fonctions réellement modifiées depuis le dernier commit :

fonctions/
├── facturation/
│   ├── creer-facture/
│   │   ├── app.mjs
│   │   └── package.json
│   └── envoyer-rappel/
│       ├── app.mjs
│       └── package.json
├── authentification/
│   └── verifier-token/
│       ├── app.mjs
│       └── package.json
└── partage/
    └── couche-utils/
        └── nodejs/
            └── logger.mjs

Le dossier partage/couche-utils illustre un Lambda Layer commun (la fonction de logStructure vue à l’étape 8, par exemple), référencé par toutes les fonctions du projet sans dupliquer le code. Cette organisation limite aussi le rayon d’impact d’une erreur de configuration IAM : chaque fonction garde un rôle et une politique dédiés, même quand elles vivent dans le même dépôt de code.

Dépannage : 8 problèmes courants et leurs solutions

  • Erreur « AccessDeniedException » au déploiement : le profil AWS CLI utilisé n’a pas les droits IAM pour créer des rôles ou des fonctions Lambda. Vérifiez la politique attachée à l’utilisateur ou au rôle qui exécute sam deploy.
  • Erreur 502 « Bad Gateway » sur l’API : le format de retour de la fonction ne correspond pas à ce qu’attend API Gateway (il manque statusCode ou body dans l’objet retourné). Vérifiez que le handler retourne bien un objet avec les clés statusCode, headers et body.
  • Timeout systématique après 3 secondes : le timeout par défaut d’API Gateway est de 29 secondes, mais celui de la fonction Lambda peut être plus bas dans le template.yaml. Augmentez la valeur Timeout ou identifiez l’appel réseau qui bloque (souvent une connexion à une base de données sans pool configuré).
  • « Task timed out » alors que le code semble rapide : la fonction est probablement dans un VPC et n’arrive pas à joindre Internet (pas de NAT Gateway) pour un appel à un service externe. Ajoutez un VPC endpoint ou une passerelle NAT selon le besoin.
  • Cold start anormalement long malgré arm64 : le package déployé contient des dépendances inutiles. Lancez du -sh hello-world/node_modules et retirez tout ce qui n’est pas requis à l’exécution.
  • Erreur 429 « Too Many Requests » sous charge modérée : le quota de concurrence réservée est probablement trop bas, ou une autre fonction du compte consomme le quota partagé. Vérifiez les métriques CloudWatch ConcurrentExecutions.
  • Les logs n’apparaissent pas dans CloudWatch : le rôle d’exécution de la fonction n’a pas la permission logs:CreateLogStream/logs:PutLogEvents. SAM l’ajoute par défaut, mais un rôle personnalisé peut l’omettre.
  • « sam local start-api » ne trouve pas le handler : le champ Handler du template.yaml ne correspond pas au nom réel du fichier ou de la fonction exportée. Pour app.mjs avec export const handler, la valeur correcte est app.handler.

Questions fréquentes

Quelle est la différence entre AWS Lambda et Cloudflare Workers ?

Cloudflare Workers exécute du code dans des isolates V8 déployés sur des centaines de points de présence edge, avec un cold start quasi nul mais un accès plus limité à l’écosystème AWS (VPC, RDS, EFS). Lambda tourne dans des micro-VM Firecracker au sein d’une région AWS, avec un cold start plus élevé mais une intégration native à tous les services AWS.

Node.js 26 est-il prêt pour la production sur Lambda ?

Non, pas encore au 26 août 2026 : il s’agit d’une préversion publique lancée le 15 août 2026. Les runtimes stables recommandés restent Node.js 22.x et Node.js 24.x.

Faut-il toujours mettre une fonction Lambda dans un VPC ?

Non. N’utilisez un VPC que si la fonction doit accéder à une ressource privée comme une instance RDS ou un cache ElastiCache. Un rattachement VPC ajoute de la latence d’initialisation, donc évitez-le pour les fonctions qui n’appellent que des services publics AWS (S3, DynamoDB via leurs endpoints publics, API externes).

Comment réduire la facture Lambda sans changer de fournisseur ?

Passez à l’architecture ARM Graviton, ajustez la mémoire allouée avec un outil de tuning plutôt qu’une valeur arbitraire, et fixez un timeout réaliste pour éviter qu’une fonction bloquée ne consomme des Go-secondes inutilement.

Quelle est la limite de concurrence par défaut sur un compte AWS ?

1 000 exécutions simultanées partagées entre toutes les fonctions Lambda d’une même région sur un compte standard. Ce quota peut être augmenté sur demande auprès du support AWS, et il est recommandé de réserver de la concurrence dédiée aux fonctions critiques pour éviter qu’elles ne soient throttlées par le trafic d’autres fonctions.

SAM ou Terraform pour déployer des fonctions Lambda ?

SAM est plus rapide à prendre en main pour des projets purement serverless, avec des commandes intégrées comme sam local start-api pour tester avant déploiement. Terraform (ou OpenTofu) convient mieux si votre infrastructure mélange Lambda avec d’autres ressources cloud gérées en dehors de l’écosystème CloudFormation.

Comment tester une fonction Lambda sans la déployer à chaque fois ?

Utilisez sam local start-api avec Docker pour émuler API Gateway et Lambda en local, complété par des tests unitaires exécutés directement sur le handler avec node --test. Réservez le déploiement réel aux validations finales avant mise en production.

Les fonctions Lambda sont-elles concernées par le Cyber Resilience Act européen ?

Toute application déployée en production, y compris serverless, entre dans le périmètre des obligations de sécurité par conception introduites par le CRA. Cela inclut la gestion des vulnérabilités des dépendances packagées dans vos fonctions, un sujet traité plus en détail dans notre article sur la signature numérique obligatoire sous le CRA.

Pour aller plus loin sur l’écosystème cloud et les architectures serverless :