Api

Builder Chain

API reference for the nuxt-safe-action builder chain — schema, outputSchema, use, metadata, and action methods for composing type-safe server actions.

Builder Chain

Actions are built using a chainable API. Each method returns a new builder with the configuration applied.

Methods

MethodDescription
.schema(zodSchema)Set input validation schema
.outputSchema(zodSchema)Set output validation schema
.use(middleware)Add middleware to the chain
.metadata(meta)Attach metadata (accessible in middleware)
.action(handler)Define the action handler (terminal)

.schema()

Sets the Zod schema used to validate input before the handler runs.

.schema(zodSchema: ZodType)

Parameters:

ParameterTypeDescription
zodSchemaZodTypeAny Zod schema (object, string, array, etc.)

Example:

actionClient
  .schema(z.object({
    title: z.string().min(1).max(200),
    body: z.string().min(1),
  }))
  .action(async ({ parsedInput }) => {
    // parsedInput is typed as { title: string; body: string }
  })

If validation fails, the errors are returned to the client as validationErrors — the handler is never called.

.outputSchema()

Sets the Zod schema used to validate the action's return value.

.outputSchema(zodSchema: ZodType)

Parameters:

ParameterTypeDescription
zodSchemaZodTypeAny Zod schema to validate the output

Example:

actionClient
  .schema(z.object({ id: z.string() }))
  .outputSchema(z.object({
    name: z.string(),
    email: z.string().email(),
  }))
  .action(async ({ parsedInput }) => {
    const user = await db.user.findUnique({ where: { id: parsedInput.id } })
    return { name: user.name, email: user.email }
  })

.use()

Adds middleware to the action chain. Middleware runs in order before the handler.

.use(middleware: MiddlewareFunction)

Middleware function signature:

async ({ ctx, next, event, metadata, clientInput }) => {
  return next({ ctx: { ...ctx, newData: 'value' } })
}

Middleware parameters:

ParameterTypeDescription
ctxobjectContext from previous middleware
next(opts: { ctx }) => PromiseContinue to next middleware or handler
eventH3EventH3 request event
metadataobjectAction metadata
clientInputunknownRaw input before validation

Example:

actionClient
  .use(async ({ next, event }) => {
    const session = await getUserSession(event)
    if (!session) throw new Error('Unauthorized')
    return next({ ctx: { userId: session.user.id } })
  })
Middleware must always call next(). Failing to do so will throw an error.

.metadata()

Attaches metadata to the action. This metadata is available in middleware via the metadata parameter.

.metadata(meta: Record<string, unknown>)

Example:

actionClient
  .metadata({ requiredRole: 'admin', rateLimit: 10 })
  .schema(z.object({ userId: z.string() }))
  .action(async ({ parsedInput }) => { ... })

.action()

Defines the action handler. This is the terminal method — it creates the action.

.action(handler: ActionHandler)

Handler function signature:

async ({ parsedInput, ctx }) => {
  return { /* result */ }
}

Handler parameters:

ParameterTypeDescription
parsedInputTInputValidated input (typed from .schema())
ctxobjectContext from the middleware chain

Example:

actionClient
  .schema(z.object({ name: z.string() }))
  .action(async ({ parsedInput }) => {
    return { greeting: `Hello, ${parsedInput.name}!` }
  })

Chain Order

Methods can be called in any order, except .action() which must be last:

// All valid:
actionClient.schema(schema).action(handler)
actionClient.use(mw).schema(schema).action(handler)
actionClient.metadata(meta).use(mw).schema(schema).action(handler)
actionClient.schema(schema).outputSchema(outSchema).use(mw).action(handler)
Copyright © 2026