Express adapter
The @mastra/express package provides a server adapter for running Mastra with Express. For general adapter concepts (constructor options, initialization flow, etc.), see Server Adapters.
InstallationDirect link to Installation
Install the Express adapter and Express framework:
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/express@latest express
pnpm add @mastra/express@latest express
yarn add @mastra/express@latest express
bun add @mastra/express@latest express
Usage exampleDirect link to Usage example
import express from 'express'
import { MastraServer } from '@mastra/express'
import { mastra } from './mastra'
const app = express()
app.use(express.json()) // Required for body parsing
const server = new MastraServer({ app, mastra })
await server.init()
app.listen(4111, () => {
console.log('Server running on port 4111')
})
Express requires express.json() middleware for JSON body parsing. Add it before creating the MastraServer. init() doesn't start Mastra's background workers. To run scheduled workflows, agent schedules, or event listeners, call await mastra.startWorkers() after the server starts listening. See Start background workers.
Constructor parametersDirect link to Constructor parameters
app:
mastra:
prefix?:
/api/v2)openapiPath?:
/openapi.json)bodyLimitOptions?:
streamOptions?:
customRouteAuthConfig?:
METHOD:PATH (e.g., GET:/api/health). Value false makes route public, true requires auth.tools?:
taskStore?:
mcpOptions?:
setRequestAuth to control what tools see as context.mcp.extra.authInfo.Differences from HonoDirect link to Differences from Hono
| Aspect | Express | Hono |
|---|---|---|
| Body parsing | Requires express.json() | Handled by framework |
| Context storage | res.locals | c.get() / c.set() |
| Middleware signature | (req, res, next) | (c, next) |
| Streaming | res.write() / res.end() | stream() helper |
| AbortSignal | Created from res.on('close'), aborted only when the response didn't finish | c.req.raw.signal |
Adding custom routesDirect link to Adding custom routes
Add routes directly to the Express app:
const app = express()
app.use(express.json())
const server = new MastraServer({ app, mastra })
// Before init - runs before Mastra middleware
app.get('/early-health', (req, res) => res.json({ status: 'ok' }))
await server.init()
// After init - has access to Mastra context
app.get('/custom', (req, res) => {
const mastraInstance = res.locals.mastra
res.json({ agents: Object.keys(mastraInstance.listAgents()) })
})
app.listen(4111)
Routes added before init() run without Mastra context. Add routes after init() to access the Mastra instance and request context.
When you want Mastra-managed auth and route metadata such as requiresAuth, prefer registerApiRoute(). For raw Express routes mounted directly on app, use createAuthMiddleware():
import express from 'express'
import { createAuthMiddleware, MastraServer } from '@mastra/express'
import { mastra } from './mastra'
const app = express()
app.use(express.json())
const server = new MastraServer({ app, mastra })
await server.init()
app.get('/custom/protected', createAuthMiddleware({ mastra }), (req, res) => {
const user = res.locals.requestContext?.get('mastra__user')
if (!user) {
return res.status(401).json({ error: 'Unauthorized' })
}
res.json({ user })
})
app.get('/custom/public', createAuthMiddleware({ mastra, requiresAuth: false }), (req, res) => {
res.json({ ok: true })
})
createAuthMiddleware() calls the next handler without authenticating when the Mastra server has no auth config, or when the route matches a public pattern. Public patterns include the built-in defaults (/api and /api/auth/*) and any auth.public patterns you configure. In those cases mastra__user isn't set, so protected handlers should reject requests without it, as the example above does.
Accessing contextDirect link to Accessing context
In Express middleware and routes, access Mastra context via res.locals:
app.get('/custom', (req, res) => {
const mastra = res.locals.mastra
const requestContext = res.locals.requestContext
const abortSignal = res.locals.abortSignal
const agent = mastra.getAgent('myAgent')
res.json({ agent: agent.name })
})
Available properties on res.locals:
| Key | Description |
|---|---|
mastra | Mastra instance |
requestContext | Request context map |
abortSignal | Request cancellation signal |
registeredTools | Tools registered with the adapter |
taskStore | Task store for A2A operations |
customRouteAuthConfig | Per-route auth overrides |
When auth is configured, read the authenticated user with res.locals.requestContext.get('mastra__user'). Clients can't set the reserved mastra__user key through the requestContext query parameter or body. On raw Express routes, the value is only populated after createAuthMiddleware() runs, so apply it before trusting the user. Don't rely on the legacy user key for authorization. A client can supply it on routes without auth middleware.
Adding middlewareDirect link to Adding middleware
Add Express middleware before init() to run it on every request. Mastra context isn't available at that point:
const app = express()
app.use(express.json())
// Runs on every request, before Mastra context exists
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`)
next()
})
const server = new MastraServer({ app, mastra })
await server.init()
Middleware added after init() never runs for Mastra's routes. Express dispatches handlers in registration order, so middleware registered after the routes only applies to routes added later.
This adapter can't run server.middleware handlers because they use Hono's signature, and it logs a warning when that option is set. If you need Express middleware between Mastra's context step and its routes, use the manual initialization flow below.
Manual initializationDirect link to Manual initialization
For custom middleware ordering, call each method separately instead of init(). See manual initialization for details.
ExamplesDirect link to Examples
- Express Adapter: Basic Express server setup
RelatedDirect link to Related
- Server Adapters: Shared adapter concepts
- MastraServer Reference: Full API reference
- createRoute() Reference: Creating type-safe custom routes