Can you use Mastra with [insert name of tech here]? Usually, yes, it’s all part of our "open relationship" philosophy 💚.
Whether it’s model providers, gateways, workflow runners, evals, memory, or storage, Mastra lets you choose the tools that work best for you. The same flexibility applies to deployment. You’ve always been able to integrate Mastra into your own server setup, but it required a little bit of manual configuration.
We’ve now made that process much easier with Mastra Server Adapters!
What are Mastra Server Adapters?
Mastra’s new Server Adapters automatically expose your agents, workflows, tools, and MCP servers as HTTP endpoints on the server you’re already running. Our latest beta release introduces two adapter packages that make running Mastra inside an existing Express or Hono app much easier to set up and maintain.
- @mastra/express: Express server adapter
- @mastra/hono: Hono server adapter
Why not just run a separate Mastra server?
Running Mastra as its own server works great for many use cases, but it creates an extra process to deploy, monitor, log, and secure. Server Adapters remove that overhead. Your existing API routes stay as they are, and Mastra just comes along for the ride!
Using the Express and Hono adapters
Pass your Express app and mastra instance to the MastraServer constructor, call init(), and all Mastra endpoints are registered automatically alongside your existing routes. Here’s an example using the Express adapter:
1// server.ts
2
3import { db } from "./lib";
4import express, { Request, Response } from "express";
5import { MastraServer } from "@mastra/express";
6import { mastra } from "./mastra"; // src/mastra/index.ts
7
8const app = express();
9app.use(express.json());
10
11const server = new MastraServer({ app, mastra });
12await server.init();
13
14app.get("/api/users/:id", async (req: Request, res: Response) => {
15 const { id } = req.params;
16
17 const result = await db.query('SELECT * FROM users WHERE id = $1', [id]);
18 res.json(result.rows[0]);
19});
20
21app.listen(3001, () => {
22 console.log("Server running on port 3001");
23});
Using Hono?
If you’re using Hono, the setup is the same as the Express example shown above. Read more about the Mastra Hono Adapter in our docs.
Mastra API Endpoints
By default Mastra endpoints are added under /api and constructed using your agent's or workflow's ID. Our default weather-agent, for example, is available at /api/agents/weather-agent/.
1const response = await fetch('/api/agents/weather-agent/generate', {
2 method: 'POST',
3 headers: {
4 'Content-Type': 'application/json',
5 },
6 body: JSON.stringify({
7 messages: [
8 {
9 role: 'user',
10 content: 'What is the weather in London?'
11 }
12 ]
13 })
14});
15
16const data = await response.json();
17console.log(data.text);
Route prefixes
If you need more control over your Mastra endpoints, for example to introduce API versioning, you can use the prefix option.
1const server = new MastraServer({
2 app,
3 mastra,
4 prefix: '/api/v2'
5});
Where you init() matters!
Server Adapters wrap your existing app, but where you call init() determines how much of your server configuration Mastra endpoints inherit.
Without configuration inheritance
In this example, Mastra endpoints wouldn’t inherit authentication because init() is run before the auth middleware has been defined.
1// server.ts
2
3const app = express();
4app.use(express.json());
5
6// Without auth, Mastra endpoints will not require authentication
7const server = new MastraServer({ app, mastra });
8await server.init();
9
10// Auth middleware: applies to routes added after this
11app.use((req: Request, res: Response, next: NextFunction) => {
12 const authHeader = req.headers.authorization;
13 if (!authHeader) {
14 return res.status(401).json({ error: "Unauthorized" });
15 }
16 next();
17});
18
19// Authenticated route
20app.get("/api/users/:id", async (req: Request, res: Response) => {
21 res.json({ id: req.params.id });
22});
With configuration inheritance
In this example, Mastra endpoints would inherit authentication because init() is run after the auth middleware has been defined.
1// server.ts
2
3const app = express();
4app.use(express.json());
5
6
7const server = new MastraServer({ app, mastra });
8
9// Auth middleware: applies to routes added after this
10app.use((req: Request, res: Response, next: NextFunction) => {
11 const authHeader = req.headers.authorization;
12 if (!authHeader) {
13 return res.status(401).json({ error: "Unauthorized" });
14 }
15 next();
16});
17
18// With auth, Mastra endpoints will require authentication
19await server.init();
20
21// Authenticated route
22app.get("/api/users/:id", async (req: Request, res: Response) => {
23 res.json({ id: req.params.id });
24});
Manual initialization
For more control over middleware ordering, you can manually initialize each of the Server Adapter methods separately: registerContextMiddleware(), registerAuthMiddleware(), and registerRoutes(). This lets you insert your own middleware between Mastra's context, auth, and route registration steps.
Want to build your own Server Adapter?
If you need even more control and want to roll your own Server Adapter, you can now extend MastraServer to create a custom solution. We’re open to contributions too, so feel free to submit a PR!
OpenAPI included!
And if you need it, the openapiPath option will create an OpenAPI spec you can fetch directly, for example at http://localhost:3001/openapi.json.
1// server.ts
2
3const server = new MastraServer({
4 app,
5 mastra,
6 openapiPath: '/openapi.json',
7});
Experienced bundling issues?
Bundling usually works, but when it doesn't, there wasn't an easy off-ramp. With no Mastra bundling step, Server Adapters let you stay in your lane. You run TypeScript directly (for example with tsx), and your monorepo, workspace dependencies, and TypeScript config work exactly as they already do. When it's time to bundle, Mastra just hops in.
Next stop: v1
Server Adapters are another important milestone on the journey to v1 (on track for release early 2026) and the open road awaits! If you'd like to take Server Adapters for a test drive (or explore the latest features), start with our current @beta:
npm create mastra@beta
Check out our Upgrade to Mastra v1 migration guide, and subscribe to our newsletter to get the latest Mastra updates first.
Peace ✌️