Skip to main content
Mastra 1.0 is available 🎉 Read announcement

Request Context

Agents, tools, and workflows can all accept RequestContext as a parameter, making request-specific values available to the underlying primitives.

When to use RequestContext
Direct link to when-to-use-requestcontext

Use RequestContext when a primitive's behavior should change based on runtime conditions. For example, you might switch models or storage backends based on user attributes, or adjust instructions and tool selection based on language.

note

Note: RequestContext is primarily used for passing data into specific requests. It's distinct from agent memory, which handles conversation history and state persistence across multiple calls.

Setting values
Direct link to Setting values

Pass requestContext into an agent, network, workflow, or tool call to make values available to all underlying primitives during execution. Use .set() to define values before making the call.

The .set() method takes two arguments:

  1. key: The name used to identify the value.
  2. value: The data to associate with that key.
import { RequestContext } from "@mastra/core/request-context";

export type UserTier = {
"user-tier": "enterprise" | "pro";
};

const requestContext = new RequestContext<UserTier>();
requestContext.set("user-tier", "enterprise");

const agent = mastra.getAgent("weatherAgent");
await agent.generate("What's the weather in London?", {
requestContext,
});

const routingAgent = mastra.getAgent("routingAgent");
routingAgent.network("What's the weather in London?", {
requestContext,
});

const run = await mastra.getWorkflow("weatherWorkflow").createRun();
await run.start({
inputData: {
location: "London",
},
requestContext,
});
await run.resume({
resumeData: {
city: "New York",
},
requestContext,
});

await weatherTool.execute(
{ location: "London" },
{ requestContext },
);

Setting values based on request headers
Direct link to Setting values based on request headers

You can populate requestContext dynamically in server middleware by extracting information from the request. In this example, the temperature-unit is set based on the Cloudflare CF-IPCountry header to ensure responses match the user's locale.

src/mastra/index.ts
import { Mastra } from "@mastra/core";
import { RequestContext } from "@mastra/core/request-context";
import { testWeatherAgent } from "./agents/test-weather-agent";

export const mastra = new Mastra({
agents: { testWeatherAgent },
server: {
middleware: [
async (context, next) => {
const country = context.req.header("CF-IPCountry");
const requestContext = context.get("requestContext");

requestContext.set(
"temperature-unit",
country === "US" ? "fahrenheit" : "celsius",
);

await next();
},
],
},
});
info

Visit Middleware for how to use server middleware.

Accessing values with agents
Direct link to Accessing values with agents

You can access the requestContext argument from any supported configuration options in agents. These functions can be sync or async. Use the .get() method to read values from requestContext.

src/mastra/agents/weather-agent.ts
export type UserTier = {
"user-tier": "enterprise" | "pro";
};

export const weatherAgent = new Agent({
id: "weather-agent",
name: "Weather Agent",
instructions: async ({ requestContext }) => {
const userTier = requestContext.get("user-tier") as UserTier["user-tier"];

if (userTier === "enterprise") {}
},
model: ({ requestContext }) => {},
tools: ({ requestContext }) => {},
memory: ({ requestContext }) => {},
});

You can also use requestContext with other options like agents, workflows, scorers, inputProcessors, and outputProcessors.

Dynamic instructions
Direct link to Dynamic instructions

Agent instructions can be provided as an async function, enabling you to resolve prompts dynamically at runtime. Combined with requestContext, this enables patterns like:

  • Personalization: Tailor instructions based on user attributes, preferences, or tier
  • Localization: Adjust tone, language, or behavior based on locale
  • A/B testing: Serve different prompt variants for experimentation
  • External prompt management: Fetch prompts from registry services without redeploying
src/mastra/agents/dynamic-agent.ts
import { Agent } from "@mastra/core/agent";

export const dynamicAgent = new Agent({
id: "dynamic-agent",
name: "Dynamic Agent",
instructions: async ({ requestContext }) => {
const userTier = requestContext?.get("user-tier");
const locale = requestContext?.get("locale");

// Personalize based on user tier
const basePrompt = userTier === "enterprise"
? "You are a premium support agent. Provide detailed, thorough responses with technical depth."
: "You are a helpful assistant. Be concise and friendly.";

// Localize behavior
const localeInstructions = locale === "ja"
? "Respond in Japanese using formal keigo."
: "";

return `${basePrompt} ${localeInstructions}`.trim();
},
model: "openai/gpt-5.1",
});

Fetching from a prompt registry
Direct link to Fetching from a prompt registry

If your organization uses a prompt registry service for central prompt management, you can fetch instructions at runtime. This allows you to update prompts without redeploying, run experiments with variants, and track prompt usage across your agents.

src/mastra/agents/registry-agent.ts
import { Agent } from "@mastra/core/agent";

// Your prompt registry client
import { promptRegistry } from "../lib/prompt-registry";

export const registryAgent = new Agent({
id: "registry-agent",
name: "Registry Agent",
instructions: async ({ requestContext }) => {
const prompt = await promptRegistry.getPrompt({
promptId: "customer-support-agent",
// Pass context for variant selection or tracking
variant: requestContext?.get("experiment-variant"),
userId: requestContext?.get("user-id"),
});

return prompt.content;
},
model: "openai/gpt-5.1",
});
info

Visit Agent for a full list of configuration options.

Accessing values from workflow steps
Direct link to Accessing values from workflow steps

You can access the requestContext argument from a workflow step's execute function. This function can be sync or async. Use the .get() method to read values from requestContext.

src/mastra/workflows/weather-workflow.ts
export type UserTier = {
"user-tier": "enterprise" | "pro";
};

const stepOne = createStep({
id: "step-one",
execute: async ({ requestContext }) => {
const userTier = requestContext.get("user-tier") as UserTier["user-tier"];

if (userTier === "enterprise") {}
},
});
info

Visit createStep() for a full list of configuration options.

Accessing values with tools
Direct link to Accessing values with tools

You can access the requestContext argument from a tool's execute function. This function is async. Use the .get() method to read values from requestContext.

src/mastra/tools/weather-tool.ts
export type UserTier = {
"user-tier": "enterprise" | "pro";
};

export const weatherTool = createTool({
id: "weather-tool",
execute: async (inputData, context) => {
const userTier = context?.requestContext?.get("user-tier") as UserTier["user-tier"] | undefined;

if (userTier === "enterprise") {}
},
});
info

Visit createTool() for a full list of configuration options.

Reserved keys
Direct link to Reserved keys

Mastra reserves special context keys for security purposes. When set by middleware, these keys take precedence over client-provided values. The server automatically validates ownership and returns 403 errors when users attempt to access resources they don't own.

import {
MASTRA_RESOURCE_ID_KEY,
MASTRA_THREAD_ID_KEY,
} from "@mastra/core/request-context";

// In middleware: force memory operations to use authenticated user's ID
requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);

// In middleware: set validated thread ID
requestContext.set(MASTRA_THREAD_ID_KEY, threadId);
KeyPurpose
MASTRA_RESOURCE_ID_KEYForces all memory operations to use this resource ID. The server validates that accessed threads belong to this resource and returns 403 if not.
MASTRA_THREAD_ID_KEYForces thread operations to use this thread ID, overriding client-provided values

These keys are used to implement user isolation in multi-tenant applications. See Authorization middleware for usage examples.

TypeScript support
Direct link to TypeScript support

When you provide a type parameter to RequestContext, all methods are fully typed:

import { RequestContext } from "@mastra/core/request-context";

type MyContext = {
userId: string;
maxTokens: number;
isPremium: boolean;
};

const ctx = new RequestContext<MyContext>();

// set() enforces correct value types
ctx.set("userId", "user-123"); // ✓ valid
ctx.set("maxTokens", 4096); // ✓ valid
ctx.set("maxTokens", "wrong"); // ✗ TypeScript error: expected number

// get() returns the correct type automatically
const tokens = ctx.get("maxTokens"); // inferred as number
const id = ctx.get("userId"); // inferred as string

// keys() returns typed keys
for (const key of ctx.keys()) {
// key is "userId" | "maxTokens" | "isPremium"
}

// entries() supports type narrowing
for (const [key, value] of ctx.entries()) {
if (key === "maxTokens") {
// TypeScript knows value is number here
console.log(value.toFixed(2));
}
if (key === "userId") {
// TypeScript knows value is string here
console.log(value.toUpperCase());
}
}