Aller au contenu principal

Déployer dans un Sandbox

@mastra/deployer-sandbox déploie un serveur Mastra complet, Studio inclus, dans un Sandbox de Workspace éphémère et renvoie une URL publique accessible. Les déploiements ultérieurs peuvent s’achever plus rapidement, car le déployeur ne réinstalle pas les dépendances.

Utilisez les déploiements en Sandbox pour :

  • Applications créées par un Agent : un Agent génère un projet Mastra et le déploie pour en vérifier le résultat.
  • Intégration continue (CI) : lancez un véritable serveur pour effectuer des vérifications, puis arrêtez-le.
  • Aperçus instantanés : partagez un Agent fonctionnel avec votre équipe avant la fusion.
  • Code multilocataire non fiable : exécutez pour chaque utilisateur une instance Mastra isolée de votre infrastructure.

La durée d’exécution des Sandboxes est limitée par leur Provider, et ces environnements finissent par expirer. Pour un hébergement en production, consultez la présentation du déploiement.

Sandboxes pris en charge
Lien direct vers Sandboxes pris en charge

Le déployeur fonctionne avec tout Sandbox de Workspace prenant en charge la mise en réseau (URL de ports publics) :

Les auteurs de Providers peuvent ajouter cette prise en charge en implémentant la fonctionnalité facultative networking de WorkspaceSandbox.

Démarrage rapide
Lien direct vers Démarrage rapide

Installez le déployeur et le Provider de Sandbox de votre choix. Cet exemple utilise Vercel Sandbox :

npm install @mastra/deployer-sandbox @mastra/vercel

Configurez le déployeur dans votre fichier src/mastra/index.ts. La valeur sandboxName identifie le déploiement : les déploiements suivants portant le même nom réutilisent donc le Sandbox existant.

src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { SandboxDeployer } from '@mastra/deployer-sandbox'
import { VercelSandbox } from '@mastra/vercel'

export const mastra = new Mastra({
deployer: new SandboxDeployer({
sandbox: new VercelSandbox({
sandboxName: 'my-preview',
timeout: 2_400_000, // 40 minutes
ports: [4111],
}),
}),
})

Deux contraintes sont propres à Vercel :

  • timeout ne peut pas dépasser la durée de vie maximale des Sandboxes prévue par votre forfait, soit 45 minutes avec l’offre Pro. Une valeur supérieure fait échouer le déploiement avec une erreur 400 de l’API Vercel.
  • Déclarez le port du serveur dans ports. Contrairement à E2B et Daytona, Vercel expose uniquement les ports déclarés lors de la création.

Compilez et déployez en une seule commande :

mastra build

Lorsqu’un SandboxDeployer() est configuré, mastra build crée le bundle de votre projet et le déploie dans le Sandbox. Le déploiement affiche les URL de l’API et de Studio, puis écrit un manifeste sandbox-deployment.json dans .mastra/output :

API: https://<sandbox-id>-4111.vercel.run/api
Studio: https://<sandbox-id>-4111.vercel.run

Le manifeste inclut expiresAt lorsque le Provider du Sandbox indique une date d’expiration.

Les redéploiements dans le même Sandbox ne réinstallent pas les dépendances lorsque les données d’entrée n’ont pas changé. Celles-ci comprennent package.json, les fichiers de verrouillage intégrés au bundle et la commande d’installation.

Contenu servi par les URL
Lien direct vers Contenu servi par les URL

L’URL de Studio correspond à la racine du Sandbox, sans /api. Ouvrez-la dans un navigateur pour utiliser Studio. Lorsque le déploiement est exécuté avec studio: false, la racine sert à la place la page d’accueil de Mastra.

L’URL de l’API sert uniquement de préfixe aux points de terminaison qu’elle contient, tels que /api/agents. /api ne possède pas son propre gestionnaire : son ouverture dans un navigateur renvoie donc une réponse « Not Found », même si le serveur fonctionne correctement.

Pour vérifier un déploiement, appelez directement un point de terminaison :

curl -s -X POST https://4111-<sandbox-id>.e2b.app/api/agents/weatherAgent/generate \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Weather in London"}]}' | jq -r '.text'

Identifiants des fournisseurs
Lien direct vers Identifiants des fournisseurs

Chaque Provider s’authentifie avec ses propres identifiants. Définissez ceux du Sandbox vers lequel vous effectuez le déploiement :

.env
# E2B
E2B_API_KEY=

# Daytona
DAYTONA_API_KEY=

# Vercel
VERCEL_TOKEN=
VERCEL_TEAM_ID=
VERCEL_PROJECT_ID=

Chaque Provider accepte également ces valeurs comme options de constructeur. Les installations auto-hébergées d’E2B et de Daytona utilisent E2B_DOMAIN ou DAYTONA_API_URL.

Contrairement à mastra dev, mastra build ne charge pas les fichiers .env. Le déploiement a lieu pendant la compilation : un Provider de Sandbox qui lit ses identifiants dans l’environnement, comme E2B avec E2B_API_KEY, obtient donc une valeur vide et le déploiement échoue avec une erreur d’authentification.

L’ajout de import 'dotenv/config' à src/mastra/index.ts ne résout pas le problème. Pour trouver le déployeur, la compilation extrait uniquement l’option deployer de votre fichier d’entrée et élimine tout le reste par tree-shaking, y compris cet import.

Chargez le fichier .env dans l’environnement du shell avant de lancer la compilation. dotenv-cli permet notamment de le faire :

npm install --save-dev dotenv-cli
package.json
{
"scripts": {
"deploy": "dotenv -e .env -- mastra build"
}
}

Exécutez ensuite npm run deploy. Le nom du script décrit son action, puisque mastra build effectue un déploiement dès qu’un SandboxDeployer() est configuré. Gardez-le distinct d’un simple script build afin qu’une plateforme d’hébergement ou une tâche CI exécutant npm run build ne déploie pas accidentellement un Sandbox.

Dans un environnement d’intégration continue (CI), exportez plutôt les identifiants sous forme de secrets. Quel que soit le mécanisme utilisé, les variables doivent exister dans l’environnement du shell, et pas uniquement dans le fichier .env.

Cela concerne les identifiants dont le déployeur a besoin sur votre machine. Les variables requises par le serveur déployé sont gérées séparément : le déployeur lit .env, .env.production et .env.local, puis les injecte dans le Sandbox. Consultez la section Sécurité.

Utiliser E2B
Lien direct vers Utiliser E2B

Pour E2B, l’id identifie le déploiement. Les déploiements suivants qui utilisent la même valeur se reconnectent donc au Sandbox existant, qu’il soit en cours d’exécution ou en pause.

src/mastra/index.ts
import { SandboxDeployer } from '@mastra/deployer-sandbox'
import { E2BSandbox } from '@mastra/e2b'

const deployer = new SandboxDeployer({
sandbox: new E2BSandbox({
id: 'my-preview',
template: 'base',
timeout: 3_600_000, // 1 hour
}),
})

Passez template: 'base' sauf si vous avez besoin de montages du système de fichiers. Sans cette option, le Provider crée à la première utilisation un modèle personnalisé de système de fichiers en espace utilisateur (Filesystem in Userspace, FUSE). E2B met le Sandbox en pause au lieu de l’arrêter : stop() crée un instantané de toute la machine virtuelle (VM), y compris sa mémoire et ses processus en cours. Lorsqu’un Sandbox en pause est réactivé, le serveur Mastra reprend là où il s’était arrêté, sans étape de relance comme avec Vercel.

Utiliser Daytona
Lien direct vers Utiliser Daytona

Pour Daytona, l’id identifie le déploiement. Les déploiements suivants qui utilisent la même valeur se reconnectent donc au Sandbox existant. Définissez public: true pour rendre l’URL d’aperçu accessible sans jeton.

src/mastra/index.ts
import { SandboxDeployer } from '@mastra/deployer-sandbox'
import { DaytonaSandbox } from '@mastra/daytona'

const deployer = new SandboxDeployer({
sandbox: new DaytonaSandbox({
id: 'my-preview',
public: true,
autoStopInterval: 30, // minutes
}),
})

L’arrêt d’un Sandbox Daytona conserve son système de fichiers, mais pas les processus en cours. Sa réactivation fonctionne donc comme avec Vercel : la fonction de résolution relance le serveur lorsque wake: true.

Daytona filtre le trafic sortant en fonction de la destination. Les requêtes vers certains hôtes établissent normalement une connexion via le protocole Transport Layer Security (TLS), tandis que d’autres sont réinitialisées pendant la négociation. Dans un Agent ou un Tool, ce problème se manifeste par l’erreur générique fetch failed de Node. Avant de déboguer votre code, vérifiez qu’il n’est pas en cause en exécutant curl vers le même hôte depuis le Sandbox :

const sandbox = new DaytonaSandbox({ id: 'my-preview' })
await sandbox.start()

const result = await sandbox.executeCommand('curl -v --max-time 10 https://api.example.com')
console.info(result.stdout, result.stderr)

Une erreur Connection reset by peer pendant la négociation TLS indique que le filtrage est en cause, et non votre Agent. Demandez au support de Daytona d’autoriser la destination. Les offres Daytona restreintes bloquent également les points de terminaison de stockage cloud ; les utilitaires de montage le signalent par une erreur spécifique.

Déploiement programmatique
Lien direct vers Déploiement programmatique

deployToSandbox() déploie un répertoire de sortie précompilé sans utiliser l’outil de création de bundle. Contrairement à SandboxDeployer(), il n’inclut Studio que si vous passez studio: true. Utilisez-le en CI ou depuis le code d’un Agent :

import { deployToSandbox } from '@mastra/deployer-sandbox'
import { VercelSandbox } from '@mastra/vercel'

const deployment = await deployToSandbox({
sandbox: new VercelSandbox({ sandboxName: 'ci-smoke', ports: [4111] }),
dir: '.mastra/output',
})

console.info(deployment.url) // https://<sandbox-id>-4111.vercel.run
await deployment.logs() // tail the server log
await deployment.stop() // stop the sandbox (resumable)
await deployment.destroy() // permanently delete the sandbox

Cycle de vie
Lien direct vers Cycle de vie

Gérer un déploiement
Lien direct vers Gérer un déploiement

Utilisez l’export getDeployment() réservé au serveur de @mastra/deployer-sandbox/client pour récupérer un déploiement existant. Il identifie le Sandbox à partir d’une configuration propre au Provider, comme un sandboxName Vercel ou un id E2B ou Daytona. La recherche n’est pas liée au processus qui a créé le déploiement : vous pouvez donc l’effectuer depuis un autre service côté serveur ou dans un environnement CI.

scripts/stop.ts
import { getDeployment } from '@mastra/deployer-sandbox/client'
import { VercelSandbox } from '@mastra/vercel'

const deployment = await getDeployment({
sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
port: 4111,
})

console.info(deployment.status, deployment.url)
await deployment.logs() // tail the server log
await deployment.stop() // stop the sandbox (resumable)
await deployment.destroy() // permanently delete the sandbox

Passez wake: true pour réactiver un Sandbox arrêté avant le retour de la fonction. Le serveur n’est relancé que s’il ne fonctionne pas correctement après la réactivation. Vous pouvez également utiliser les outils du Provider, par exemple vercel sandbox ls, vercel sandbox stop et vercel sandbox rm.

Expiration et URL
Lien direct vers Expiration et URL

Les Sandboxes expirent selon les limites d’exécution du Provider. Lorsque celui-ci indique une date d’expiration, le déploiement l’inscrit dans les logs et deployment.expiresAt permet d’y accéder par programmation.

L’URL d’un Sandbox peut changer lorsque celui-ci est arrêté puis réactivé. Considérez l’URL comme un détail d’acheminement et l’identité du Sandbox, par exemple son sandboxName, comme sa référence stable. Les niveaux de routage ci-dessous prennent en charge la rotation des URL.

Niveaux de routage
Lien direct vers Niveaux de routage

Niveau 1 : URL directe
Lien direct vers Niveau 1 : URL directe

Utilisez directement l’URL affichée pour le développement, les démonstrations et les environnements CI dans lesquels une nouvelle URL à chaque déploiement est acceptable.

Niveau 2 : résoudre l’URL lors de l’exécution
Lien direct vers Niveau 2 : résoudre l’URL lors de l’exécution

getDeployment() résout l’URL actuelle lors de l’exécution, de sorte que les clients ne conservent jamais une URL obsolète. Tout serveur qui connaît le nom du Sandbox peut résoudre son URL, même si sa base de code diffère de celle du projet Mastra :

app/api/agent-url/route.ts
import { getDeployment } from '@mastra/deployer-sandbox/client'
import { VercelSandbox } from '@mastra/vercel'

const deployment = await getDeployment({
sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
wake: true,
})

console.info(deployment.url, deployment.status)

Avec wake: false (valeur par défaut), le Sandbox n’est pas démarré et vous obtenez { url, status } afin de décider de l’action à effectuer. La résolution de l’URL, stop() et destroy() se connectent au Sandbox existant par son nom sans le réactiver. Les opérations de cycle de vie appliquées à un Sandbox arrêté ne le réactivent donc jamais et ne déclenchent aucune facturation. Avec wake: true, le Sandbox est réactivé et le serveur est relancé s’il ne répond pas. La nécessité de le relancer dépend du Provider : Vercel et Daytona restaurent le système de fichiers, mais pas les processus en cours, tandis qu’E2B réactive l’ensemble de la VM, y compris le processus du serveur.

attention

@mastra/deployer-sandbox/client est réservé au serveur. La résolution d’un Sandbox utilise les identifiants du Provider, qui ne doivent jamais parvenir au navigateur. Le module lève une erreur s’il est importé dans un contexte de navigateur.

Niveau 3 : URL stable pour les utilisateurs finaux
Lien direct vers Niveau 3 : URL stable pour les utilisateurs finaux

Fournissez aux utilisateurs finaux une URL stable sur votre propre domaine, puis transférez les requêtes vers le Sandbox côté serveur au moyen d’un proxy de gestionnaire de route ou d’un alias Edge Config.

L’exemple ci-dessous présente une configuration Vercel et Next.js, mais ce principe s’applique à tout framework côté serveur ou Provider capable de transférer des requêtes.

  • Proxy de gestionnaire de route. createSandboxHandler() met en cache l’URL du Sandbox et la résout de nouveau après une erreur de connexion, ce qui prend en charge la rotation des URL et les réactivations à froid :

    app/api/[...path]/route.ts
    import { createSandboxHandler, getDeployment } from '@mastra/deployer-sandbox/client'
    import { VercelSandbox } from '@mastra/vercel'

    const handler = createSandboxHandler({
    resolve: async () => {
    const deployment = await getDeployment({
    sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
    wake: true,
    })
    return deployment.url!
    },
    })

    export { handler as GET, handler as POST }
  • Alias Edge Config. Définissez l’option alias du déployeur pour que, à chaque déploiement, un élément de Vercel Edge Config pointe toujours vers l’URL actuelle :

    src/mastra/index.ts
    const deployer = new SandboxDeployer({
    sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }),
    alias: { edgeConfigId: 'ecfg_...', key: 'my-preview', token: process.env.VERCEL_TOKEN! },
    })

    Réécrivez ensuite les requêtes dans un middleware Next.js avec createSandboxProxy() :

    middleware.ts
    import { createSandboxProxy } from '@mastra/deployer-sandbox/client'

    export const middleware = createSandboxProxy({ key: 'my-preview' })
    export const config = { matcher: '/api/:path*' }

Exemple d’intégration continue
Lien direct vers Exemple d’intégration continue

Déployez un aperçu pour chaque demande de fusion :

.github/workflows/preview.yml
name: Sandbox preview
on: pull_request

jobs:
preview:
runs-on: ubuntu-latest
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx mastra build
- run: curl --fail "$(jq -r .url .mastra/output/sandbox-deployment.json)/api"

Sécurité
Lien direct vers Sécurité

  • L’URL du Sandbox est publique. Toute personne qui la connaît peut accéder à votre serveur Mastra, y compris à Studio. Activez l’authentification du serveur pour tout usage autre que des aperçus temporaires.
  • Les variables d’environnement de vos fichiers .env sont injectées dans la VM distante du Sandbox afin que le serveur puisse fonctionner. Le déploiement consigne alors un avertissement dans les logs. Ne déployez aucun secret que vous ne placeriez pas sur un serveur d’aperçu partagé.
  • Pour limiter l’accès au trafic de niveau 3, transmettez un secret à createSandboxHandler() ou à createSandboxProxy(). Ces utilitaires l’ajoutent aux requêtes transférées sous la forme d’un en-tête x-mastra-sandbox-secret. Configurez l’authentification du serveur pour exiger cet en-tête : les accès directs à l’URL du Sandbox seront alors rejetés, tandis que le trafic passant par votre domaine sera accepté.