Advanced
Metadata
Metadata lets you attach type-safe data to each action that's accessible in middleware. This is useful for logging, permission checks, rate limiting, and any cross-cutting concern that needs to know which action is running.
Setup
Define a metadata schema
Tell the client what shape metadata should have:
import { z } from "zod";
import { createSafeActionClient } from "next-safe-action";
export const actionClient = createSafeActionClient({
defineMetadataSchema() {
return z.object({
actionName: z.string(),
requiredRole: z.enum(["user", "admin"]).optional(),
});
},
});Set metadata on each action
Once a metadata schema is defined, .metadata() must be called before .action():
"use server";
export const deleteUser = actionClient
.metadata({ actionName: "deleteUser", requiredRole: "admin" })
.inputSchema(z.object({ userId: z.string() }))
.action(async ({ parsedInput }) => {
await db.user.delete({ where: { id: parsedInput.userId } });
});TypeScript enforces the metadata shape. If you forget a required field or use the wrong type, you get a compile error.
Access metadata in middleware
Metadata is available in every middleware function:
export const actionClient = createSafeActionClient({
defineMetadataSchema() {
return z.object({
actionName: z.string(),
requiredRole: z.enum(["user", "admin"]).optional(),
});
},
}).use(async ({ next, metadata }) => {
// Log which action is running
console.log(`Running action: ${metadata.actionName}`);
return next();
}).use(async ({ next, metadata, ctx }) => {
// Check permissions based on metadata
if (metadata.requiredRole && ctx.user.role !== metadata.requiredRole) {
throw new Error(`Requires ${metadata.requiredRole} role`);
}
return next();
});Use cases
| Use case | Metadata fields |
|---|---|
| Logging | actionName, category |
| Permissions | requiredRole, requiredPermissions |
| Rate limiting | rateLimit, rateLimitWindow |
| Feature flags | feature, experimentGroup |
| Analytics | trackingEvent, source |
Metadata is validated at runtime using the schema you define. If invalid metadata is passed, the action fails with a metadata validation error before any middleware runs.
See also
- Middleware — where metadata is most commonly used
defineMetadataSchema— client-level metadata schema configuration.metadata()method — API referenceActionMetadataValidationError— error thrown on invalid metadata