Express is the most popular Node.js web framework. The Express adapter lets you deploy Mastra on traditional Node.js servers with the full Express ecosystem.
Installation
npm install @mastra/express express
Basic Setup
Import dependencies
import express from 'express' ;
import { Mastra } from '@mastra/core' ;
import { MastraServer } from '@mastra/express' ;
Create Mastra instance
const mastra = new Mastra ({
// Your Mastra configuration
});
Create Express app and mount Mastra
const app = express ();
const server = new MastraServer ({ mastra , app });
app . listen ( 4111 );
Complete Example
import express from 'express' ;
import cors from 'cors' ;
import { Mastra } from '@mastra/core' ;
import { MastraServer } from '@mastra/express' ;
import { Agent } from '@mastra/core/agent' ;
import { createOpenAI } from '@ai-sdk/openai' ;
// Create an agent
const agent = new Agent ({
name: 'assistant' ,
instructions: 'You are a helpful assistant.' ,
model: createOpenAI ({
apiKey: process . env . OPENAI_API_KEY ! ,
}). chat ( 'gpt-4o' ),
});
// Create Mastra instance
const mastra = new Mastra ({
agents: { assistant: agent },
});
// Create Express app
const app = express ();
// Add middleware
app . use ( cors ());
app . use ( express . json ());
// Custom routes
app . get ( '/' , ( req , res ) => {
res . json ({ message: 'Mastra API' });
});
// Health check
app . get ( '/health' , ( req , res ) => {
res . json ({ status: 'ok' });
});
// Mount Mastra server
const server = new MastraServer ({
mastra ,
app ,
prefix: '/api/mastra' ,
});
// Start server
const port = 4111 ;
app . listen ( port , () => {
console . log ( `Server running on http://localhost: ${ port } ` );
});
Configuration Options
app
Express.Application
required
Express application instance
prefix
string
default: "/api/mastra"
URL prefix for Mastra routes
Body size limits for uploads: {
maxSize : 10 * 1024 * 1024 , // 10MB
onError : ( error ) => ({ error: 'File too large' })
}
Streaming configuration: {
redact : true // Redact sensitive data in streams
}
Middleware
CORS
import cors from 'cors' ;
app . use ( cors ({
origin: 'http://localhost:3000' ,
credentials: true ,
}));
const server = new MastraServer ({ mastra , app });
JSON Body Parser
import express from 'express' ;
app . use ( express . json ({ limit: '10mb' }));
app . use ( express . urlencoded ({ extended: true , limit: '10mb' }));
const server = new MastraServer ({ mastra , app });
Authentication
import { MastraAuthClerk } from '@mastra/auth-clerk' ;
const mastra = new Mastra ({
server: {
auth: new MastraAuthClerk (),
},
});
const app = express ();
const server = new MastraServer ({ mastra , app });
// Auth middleware is automatically added
Logging
import morgan from 'morgan' ;
app . use ( morgan ( 'combined' ));
const server = new MastraServer ({ mastra , app });
Helmet (Security)
import helmet from 'helmet' ;
app . use ( helmet ());
const server = new MastraServer ({ mastra , app });
Rate Limiting
import rateLimit from 'express-rate-limit' ;
const limiter = rateLimit ({
windowMs: 15 * 60 * 1000 , // 15 minutes
max: 100 , // max 100 requests per window
});
app . use ( '/api/' , limiter );
const server = new MastraServer ({ mastra , app });
Custom Routes
Add Custom Endpoints
const app = express ();
app . use ( express . json ());
// Custom routes before Mastra
app . get ( '/health' , ( req , res ) => {
res . json ({ status: 'ok' });
});
app . post ( '/custom/endpoint' , async ( req , res ) => {
const body = req . body ;
res . json ({ received: body });
});
// Mount Mastra
const server = new MastraServer ({ mastra , app });
Access Mastra Context
app . get ( '/custom/agent-status' , ( req , res ) => {
const mastra = res . locals . mastra ; // Access Mastra instance
const agents = Object . keys ( mastra . agents || {});
res . json ({ agents });
});
const server = new MastraServer ({ mastra , app });
Streaming
Express adapter supports SSE streaming for agent responses:
// Mastra automatically handles streaming
const response = await fetch ( 'http://localhost:4111/api/mastra/agents/assistant/stream' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
messages: [{ role: 'user' , content: 'Hello!' }],
}),
});
const reader = response . body . getReader ();
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
console . log ( new TextDecoder (). decode ( value ));
}
File Uploads
Handle file uploads with body limits:
const server = new MastraServer ({
mastra ,
app ,
bodyLimitOptions: {
maxSize: 50 * 1024 * 1024 , // 50MB
onError : ( error ) => ({
error: 'File size exceeds 50MB limit' ,
code: 'FILE_TOO_LARGE' ,
}),
},
});
Error Handling
Custom Error Handler
app . use (( err , req , res , next ) => {
console . error ( 'Error:' , err );
res . status ( err . status || 500 ). json ({
error: err . message ,
stack: process . env . NODE_ENV === 'development' ? err . stack : undefined ,
});
});
const server = new MastraServer ({ mastra , app });
404 Handler
app . use (( req , res ) => {
res . status ( 404 ). json ({ error: 'Not found' });
});
const server = new MastraServer ({ mastra , app });
HTTPS
Development
import https from 'https' ;
import fs from 'fs' ;
const options = {
key: fs . readFileSync ( 'key.pem' ),
cert: fs . readFileSync ( 'cert.pem' ),
};
const server = new MastraServer ({ mastra , app });
https . createServer ( options , app ). listen ( 443 );
Production
Use a reverse proxy like Nginx or Caddy:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:4111;
proxy_http_version 1.1 ;
proxy_set_header Upgrade $ http_upgrade ;
proxy_set_header Connection 'upgrade' ;
proxy_set_header Host $ host ;
proxy_cache_bypass $ http_upgrade ;
}
}
Testing
import request from 'supertest' ;
import express from 'express' ;
import { MastraServer } from '@mastra/express' ;
describe ( 'Mastra API' , () => {
const app = express ();
const server = new MastraServer ({ mastra , app });
it ( 'should return agents list' , async () => {
const res = await request ( app )
. get ( '/api/mastra/agents' )
. expect ( 200 );
expect ( res . body ). toHaveProperty ( 'agents' );
});
});
Best Practices
Middleware Order Matters Add middleware before mounting MastraServer: app . use ( cors ());
app . use ( express . json ());
app . use ( helmet ());
const server = new MastraServer ({ mastra , app });
Use Helmet for Security Protect against common vulnerabilities:
Enable Compression import compression from 'compression' ;
app . use ( compression ());
Set Trust Proxy When behind a reverse proxy: app . set ( 'trust proxy' , 1 );
Process Management
PM2
module.exports = {
apps : [{
name : 'mastra-api' ,
script : './dist/index.js' ,
instances : 'max' ,
exec_mode : 'cluster' ,
env : {
NODE_ENV : 'production' ,
PORT : 4111 ,
},
}],
};
pm2 start ecosystem.config.js
Systemd
/etc/systemd/system/mastra.service
[Unit]
Description =Mastra API
After =network.target
[Service]
Type =simple
User =node
WorkingDirectory =/app
ExecStart =/usr/bin/node /app/dist/index.js
Restart =always
Environment = NODE_ENV =production
[Install]
WantedBy =multi-user.target
Deployment
Docker
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 4111
CMD [ "node" , "dist/index.js" ]
Docker Compose
version : '3.8'
services :
api :
build : .
ports :
- "4111:4111"
environment :
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@postgres:5432/mastra
depends_on :
- postgres
postgres :
image : postgres:16
environment :
- POSTGRES_PASSWORD=password
volumes :
- postgres-data:/var/lib/postgresql/data
volumes :
postgres-data :
Hono Adapter Lightweight edge-optimized alternative
Authentication Add authentication to your Mastra API
Express Documentation Official Express documentation
Express Best Practices Security best practices