Hoppscotch est un client d'API open source, sous licence MIT, que vous pouvez héberger sur votre propre serveur. Il remplit le même rôle que Postman ou Insomnia (construire des requêtes HTTP, les organiser en collections, écrire des tests) avec une différence qui change tout en entreprise : vos collections, vos jetons et vos URLs internes ne quittent jamais votre infrastructure. Ce guide montre comment l'installer avec Docker Compose, écrire une collection de tests, puis rejouer ces tests en intégration continue grâce au CLI hopp. Tout a été validé sur la version 2026.6.0.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Situer Hoppscotch face à Postman, Insomnia et Bruno, et savoir quand il ne convient pas
- Auto-héberger la Community Edition avec Docker Compose, base PostgreSQL comprise
- Franchir les deux pièges qui empêchent le service de démarrer au premier lancement
- Écrire une collection de tests d'API et la rejouer en une seule commande
- Brancher ces tests sur une CI GitHub Actions qui échoue quand une API régresse
Pourquoi chercher une alternative à Postman
Section intitulée « Pourquoi chercher une alternative à Postman »Postman reste l'outil le plus répandu, mais il a progressivement déplacé son centre de gravité vers le cloud. Les collections se synchronisent sur les serveurs de l'éditeur, le mode hors ligne s'est réduit, et un compte est demandé pour les usages collaboratifs. Pour une équipe qui manipule des jetons d'authentification et des URLs d'API internes, cela signifie que des éléments sensibles transitent vers un tiers.
Hoppscotch prend le problème à l'envers. Le cœur du produit est sous licence MIT et la version dite Community Edition s'installe sur votre serveur. Vous gardez la même ergonomie (un onglet, une requête, un bouton « envoyer ») mais la donnée reste chez vous. C'est l'argument décisif dans les contextes réglementés ou simplement lorsque la politique de sécurité interdit de sortir des identifiants du réseau.
Voici comment les outils se répartissent, sans complaisance.
| Outil | Modèle | Stockage des collections | Point fort | Limite |
|---|---|---|---|---|
| Postman | Propriétaire, freemium | Cloud de l'éditeur | Écosystème très riche | La donnée sort de chez vous |
| Hoppscotch | Open source MIT | Chez vous si auto-hébergé | Léger, web, auto-hébergeable | Écosystème plus jeune |
| Insomnia | Open source, éditeur Kong | Cloud ou local | Interface soignée | Compte demandé par défaut |
| Bruno | Open source | Fichiers dans votre dépôt Git | Collections versionnées | Pas de collaboration serveur |
Le choix se fait sur un critère simple. Si vous voulez que vos collections vivent dans Git aux côtés du code, Bruno est plus direct. Si vous voulez un service partagé par l'équipe, avec des espaces de travail et une console d'administration, mais hébergé par vos soins, Hoppscotch est le bon candidat. Et si vous ne testez qu'un endpoint de temps en temps, curl ou HTTPie suffisent largement.
Prérequis
Section intitulée « Prérequis »Le lab tient sur un poste de développement ordinaire. Il vous faut :
- Docker et le plugin Compose en place, avec les bases vues dans le guide Docker Compose
- Node.js 22 minimum pour le CLI, car les versions antérieures ne sont pas supportées
- Environ 2 Go de RAM libres et les ports 3000, 3100 et 3170 disponibles
- Des notions d'API REST : méthodes HTTP, codes de statut, corps JSON
Auto-héberger Hoppscotch avec Docker Compose
Section intitulée « Auto-héberger Hoppscotch avec Docker Compose »L'image officielle est dite AIO (all-in-one) : elle embarque l'application web, la console d'administration et le backend dans un seul conteneur, qui expose trois ports distincts. Il ne manque qu'une base PostgreSQL pour stocker les comptes et les collections.
Le fichier Compose
Section intitulée « Le fichier Compose »Créez un dossier de travail et déposez-y ce fichier compose.yaml. Les images sont épinglées par empreinte (sha256), afin qu'une reconstruction six mois plus tard installe exactement la même version.
name: hoppscotch
services: db: image: postgres@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193 # postgres:17-alpine environment: POSTGRES_USER: hoppscotch POSTGRES_PASSWORD: hoppscotch POSTGRES_DB: hoppscotch volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U hoppscotch"] interval: 5s timeout: 5s retries: 10
hoppscotch: image: hoppscotch/hoppscotch@sha256:4e95eb2c49bde22b94b2aaa889b15d0a1bf995ba5c23e368f7e905d977053072 # 2026.6.0 env_file: .env restart: unless-stopped ports: - "3000:3000" # application - "3100:3100" # console d'administration - "3170:3170" # backend (API et GraphQL) depends_on: db: condition: service_healthy
volumes: db-data:La directive restart: unless-stopped n'est pas un confort : elle est indispensable, pour une raison expliquée juste après.
Le fichier de configuration
Section intitulée « Le fichier de configuration »Hoppscotch se configure entièrement par variables d'environnement. Voici le minimum viable pour un lab local, dans un fichier .env placé à côté du compose.yaml.
DATABASE_URL=postgresql://hoppscotch:hoppscotch@db:5432/hoppscotch
# Secrets : à régénérer avant toute mise en service réelleJWT_SECRET=changez_moi_absolumentSESSION_SECRET=changez_moi_aussiDATA_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef
TOKEN_SALT_COMPLEXITY=10MAGIC_LINK_TOKEN_VALIDITY=3REFRESH_TOKEN_VALIDITY=604800000ACCESS_TOKEN_VALIDITY=86400000
# false uniquement parce que le lab tourne en HTTP sur localhostALLOW_SECURE_COOKIES=false
VITE_ALLOWED_AUTH_PROVIDERS=EMAILREDIRECT_URL=http://localhost:3000WHITELISTED_ORIGINS=http://localhost:3170,http://localhost:3000,http://localhost:3100
VITE_BASE_URL=http://localhost:3000VITE_SHORTCODE_BASE_URL=http://localhost:3000VITE_ADMIN_URL=http://localhost:3100VITE_BACKEND_GQL_URL=http://localhost:3170/graphqlVITE_BACKEND_WS_URL=ws://localhost:3170/graphqlVITE_BACKEND_API_URL=http://localhost:3170/v1DATA_ENCRYPTION_KEY doit faire exactement 32 caractères : c'est elle qui chiffre les données sensibles en base. Les variables préfixées VITE_ sont lues par le navigateur, pas par le serveur. Elles doivent donc contenir les URLs telles que votre poste les voit. Si vous publiez l'application sur un autre port que 3000, ou derrière un nom de domaine, ces valeurs doivent suivre, faute de quoi l'interface s'affichera mais appellera un backend introuvable.
Démarrer, dans le bon ordre
Section intitulée « Démarrer, dans le bon ordre »Deux comportements du produit surprennent au premier lancement. Les connaître évite une demi-heure de perplexité.
-
Jouer les migrations de base avant tout démarrage. Le backend refuse de démarrer tant que le schéma n'existe pas en base, avec le message
Database migration not found. La documentation suggère d'entrer dans le conteneur, ce qui est impossible puisqu'il vient précisément de s'arrêter. Passez par un conteneur jetable :Fenêtre de terminal docker compose run --rm --entrypoint sh hoppscotch \-c "cd /dist/backend && pnpm exec prisma migrate deploy"La sortie doit se terminer par
All migrations have been successfully applied. -
Lancer la pile :
Fenêtre de terminal docker compose up -d -
Comprendre le premier arrêt volontaire. Au tout premier démarrage, le backend remplit sa table de configuration, affiche
Stopping app in 5 seconds...puis s'arrête de lui-même. C'est voulu. Sansrestart: unless-stopped, le conteneur reste mort et vous croyez à un plantage. Avec la politique de redémarrage, Docker le relance et l'instance devient saine. -
Vérifier que le service répond :
Fenêtre de terminal curl -s http://localhost:3170/pingLa réponse attendue est
Success. L'application est alors accessible surhttp://localhost:3000et la console d'administration surhttp://localhost:3100.
L'interface reprend les codes d'un client d'API classique : la requête au centre, les collections à droite, et les onglets pour le corps, les en-têtes, l'authentification et les scripts de test.

La console d'administration, elle, vous accueille au premier accès avec un assistant de configuration. Il réclame un moyen d'authentification : soit un relais SMTP (les comptes se connectent alors par lien envoyé par courriel), soit un fournisseur OAuth. Tant que ce choix n'est pas fait, personne ne peut créer de compte.

Le premier compte créé devient administrateur. Sur une instance réelle, renseignez les variables MAILER_* vers votre relais SMTP. Pour un lab, le plus simple est d'ajouter un conteneur Mailpit, qui capture les messages au lieu de les envoyer : les liens de connexion s'affichent dans une boîte locale, sans dépendre d'un vrai serveur de mail.
Écrire des tests et les rejouer en une commande
Section intitulée « Écrire des tests et les rejouer en une commande »C'est ici que Hoppscotch dépasse le simple client graphique. Une collection est un fichier JSON qui contient des requêtes et, pour chacune, un script de test en JavaScript. Le CLI hopp rejoue ce fichier hors de tout navigateur, ce qui le rend utilisable dans une chaîne d'intégration continue.
Installer le CLI
Section intitulée « Installer le CLI »Le CLI exige Node.js 22 ou plus récent. Plutôt que d'installer Node globalement, épinglez la version par projet avec mise, puis installez le paquet en fixant sa version.
mise use node@22.22.0npm install -g @hoppscotch/cli@0.31.3hopp -vNotez le drapeau : c'est bien -v ou --ver, et non --version que la documentation laisse supposer. La version affichée porte encore la mention ALPHA, ce qui invite à épingler la version du CLI dans vos pipelines plutôt qu'à suivre aveuglément la dernière publiée.
La collection et ses tests
Section intitulée « La collection et ses tests »Une collection minimale ressemble à ceci. Elle interroge une API de démonstration, vérifie le code de statut et le contenu de la réponse. La variable baseUrl, écrite entre doubles chevrons dans le champ endpoint, sera fournie par un fichier d'environnement séparé.
{ "v": 6, "name": "API httpbin", "folders": [], "auth": { "authType": "inherit", "authActive": true }, "headers": [], "requests": [ { "v": "11", "id": "req-status", "name": "Le service repond", "method": "GET", "endpoint": "<<baseUrl>>/get", "params": [], "headers": [], "preRequestScript": "", "testScript": "pw.test(\"Le code de retour est 200\", () => {\n pw.expect(pw.response.status).toBe(200);\n});", "auth": { "authType": "none", "authActive": false }, "body": { "contentType": null, "body": null }, "requestVariables": [], "responses": {} } ]}Deux détails de format coûtent cher, car ils ne sont pas documentés et le message d'erreur ne les désigne pas. Les champs auth et headers sont obligatoires au niveau de la collection, pas seulement au niveau de chaque requête : sans eux, le CLI rejette le fichier avec un laconique MALFORMED_COLLECTION. En pratique, exportez une collection depuis l'interface plutôt que de l'écrire à la main, puis versionnez ce fichier dans votre dépôt.
Le fichier d'environnement, lui, porte les valeurs qui changent d'un contexte à l'autre. Chaque variable veut un couple initialValue et currentValue : l'ancien format à clé value, encore visible dans de nombreux tutoriels, produit une erreur MALFORMED_ENV_FILE.
{ "v": 2, "id": "env-lab", "name": "lab", "variables": [ { "key": "baseUrl", "initialValue": "http://localhost:8080", "currentValue": "http://localhost:8080", "secret": false } ]}Les scripts de test utilisent l'espace de noms pw. Vous disposez de pw.test() pour nommer un cas, de pw.expect() pour l'assertion, et de pw.response pour accéder au statut et au corps de la réponse. Un test qui vérifie une valeur métier s'écrit aussi simplement que cela :
pw.test("Le corps envoye est bien recu", () => { pw.expect(pw.response.body.json.equipe).toBe("plateforme");});Rejouer la collection
Section intitulée « Rejouer la collection »Une seule commande suffit, l'environnement étant passé avec -e :
hopp test -e env-lab.json httpbin.jsonLa sortie liste chaque requête, chaque assertion, puis un récapitulatif du type Test Cases: 0 failed 5 passed. Le point qui compte pour l'automatisation est ailleurs : le CLI renvoie 0 si tout passe et 1 dès qu'un test échoue. C'est ce code de retour qui permettra à une CI de bloquer une régression, sans avoir à analyser la sortie texte.
Brancher les tests sur une intégration continue
Section intitulée « Brancher les tests sur une intégration continue »Comme le CLI est un simple paquet npm et qu'il respecte les codes de retour, l'intégrer à GitHub Actions tient en quelques lignes. Le drapeau --reporter-junit produit en plus un rapport JUnit que la plateforme sait afficher.
name: Tests API
on: push: branches: [main] pull_request:
permissions: {}
jobs: hopp: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: '22'
- name: Installer le CLI Hoppscotch run: npm install -g @hoppscotch/cli@0.31.3
- name: Jouer la collection run: hopp test -e collections/env-ci.json collections/httpbin.json --reporter-junit rapport.xml
- name: Publier le rapport if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: rapport-tests-api path: rapport.xmlLes actions sont épinglées par empreinte de commit et les permissions réduites au strict nécessaire, conformément à ce que vérifient des outils comme actionlint. L'étape de publication porte if: always() pour que le rapport remonte même quand les tests échouent, moment où il est justement le plus utile.
Gardez un fichier d'environnement distinct par contexte (env-ci.json, env-recette.json) : seule l'URL de base change, la collection reste la même. Les valeurs sensibles, elles, n'ont rien à faire dans ces fichiers versionnés ; passez-les par les secrets de la plateforme et marquez la variable correspondante en secret.
Sécuriser une instance exposée
Section intitulée « Sécuriser une instance exposée »Un lab en localhost tolère les raccourcis, une instance partagée non. Quatre points méritent votre attention avant d'ouvrir le service à l'équipe.
Les secrets du fichier .env doivent être générés, jamais recopiés d'un tutoriel. JWT_SECRET, SESSION_SECRET et surtout DATA_ENCRYPTION_KEY protègent les jetons stockés en base : une valeur d'exemple laissée en place revient à publier vos identifiants d'API. Un openssl rand -hex 16 fournit les 32 caractères attendus par la clé de chiffrement.
Le service doit tourner derrière HTTPS, avec un reverse proxy qui termine le TLS. Repassez alors ALLOW_SECURE_COOKIES à true : c'est cette variable qui empêche le cookie de session de circuler en clair. Les URLs VITE_* et WHITELISTED_ORIGINS doivent refléter le nom de domaine public, pas localhost.
La console d'administration, sur le port 3100, donne accès à la configuration de l'instance et à la liste des comptes. Elle n'a aucune raison d'être jointe depuis Internet : restreignez-la au réseau interne ou placez-la derrière une authentification supplémentaire. Enfin, RATE_LIMIT_TTL et RATE_LIMIT_MAX plafonnent le nombre de requêtes par adresse IP et limitent l'intérêt d'une attaque par force brute sur les liens de connexion.
Dépannage
Section intitulée « Dépannage »Les erreurs rencontrées lors de la mise en place de ce guide, et ce qui les corrige.
| Symptôme | Cause | Solution |
|---|---|---|
Database migration not found puis arrêt | Le schéma n'existe pas encore en base | Jouer prisma migrate deploy dans un conteneur jetable avant le démarrage |
Le conteneur s'arrête avec le code 0 après Stopping app in 5 seconds... | Arrêt volontaire après l'initialisation de la configuration | Ajouter restart: unless-stopped au service |
| L'interface s'affiche mais aucune requête ne part | Les variables VITE_* pointent vers un backend inaccessible | Aligner VITE_BACKEND_API_URL et WHITELISTED_ORIGINS sur les ports réellement publiés |
MALFORMED_COLLECTION | auth ou headers absents au niveau de la collection | Ajouter les deux champs, ou réexporter la collection depuis l'interface |
MALFORMED_ENV_FILE | Format d'environnement obsolète à clé value | Utiliser initialValue et currentValue |
Bind for 0.0.0.0:3000 failed | Le port est déjà pris par un autre service | Changer le port publié et les variables VITE_* correspondantes |
| Aucun courriel de connexion ne parvient | Relais SMTP absent ou mal configuré | Vérifier les variables MAILER_*, ou utiliser mailpit en local |
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les réponses ci-dessous reprennent les questions les plus posées sur Hoppscotch : son modèle open source, son positionnement face à Postman et les erreurs de format qui bloquent le CLI. Chacune renvoie à la section du guide qui la traite en détail.
hoppscotch/hoppscotch, qui expose trois ports : 3000 pour l'application, 3100 pour la console d'administration et 3170 pour le backend. Deux étapes sont indispensables : jouer les migrations de base avant le premier démarrage (prisma migrate deploy), et déclarer restart: unless-stopped, car le backend s'arrête volontairement après avoir initialisé sa configuration.hopp, installé par npm et compatible Node.js 22 minimum. La commande hopp test -e env.json collection.json rejoue une collection hors navigateur. Elle renvoie le code de retour 1 dès qu'un test échoue, ce qui suffit à faire échouer un pipeline, et l'option --reporter-junit produit un rapport JUnit exploitable par votre plateforme d'intégration continue.auth et headers au niveau de la collection, et pas uniquement dans chaque requête. Une collection écrite à la main sans ces deux champs est rejetée. L'erreur voisine MALFORMED_ENV_FILE vient du fichier d'environnement : chaque variable doit porter un couple initialValue et currentValue, l'ancien format à clé value n'étant plus accepté. Le plus sûr reste d'exporter la collection depuis l'interface puis de la versionner.À retenir
Section intitulée « À retenir »- Hoppscotch est un client d'API open source (MIT) qui s'auto-héberge : vos collections et vos jetons restent chez vous.
- L'installation passe par une image AIO et une base PostgreSQL, avec trois ports distincts pour l'application, l'administration et le backend.
- Deux pièges bloquent le premier démarrage : les migrations à jouer avant tout lancement et l'arrêt volontaire du backend qui impose une politique de redémarrage.
- Les variables
VITE_*sont lues par le navigateur : elles doivent refléter les URLs réellement publiées, sinon l'interface appelle un backend fantôme. - Le CLI
hopprejoue une collection hors navigateur et renvoie 1 en cas d'échec, ce qui suffit à casser une CI sur une régression d'API. - Le format des fichiers est strict et peu documenté :
authetheadersau niveau collection,initialValueetcurrentValuecôté environnement.