Skip to main content
Version: Next

createServerAction

The createServerAction function is returned by createClient and is used to define individual server actions in your application.

Each server action:

  • Validates the input using a Zod schema
  • Automatically applies shared middleware, context, and error handling defined in createClient
  • Accepts optional options like clear to reset form state on error
  • Returns a structured Response object compatible with useActionState on the client

Basic Usage

app/_lib/actions/sign-in.ts
"use server";

import { z } from "zod";
import { createServerAction } from "../utils/server-actions";

const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
});

export const signIn = createServerAction<typeof schema>(
schema,
async (values) => {
// Your server-side logic here
return { ok: true };
}
);

Function Signature

function createServerAction<S extends ZodSchema, R = object>(
schema: S,
handler: (values: z.infer<S>, context: C) => Promise<Response<S, R>>,
options?: CreateServerActionOptions
): (
prev: Response<S, R>,
data: FormData
) => Promise<Response<S, R>>;

Parameters

  • schema: A Zod schema used to validate the incoming form data.
  • handler: A function that receives the validated values and the context (if defined). It must return a Response object.
  • options (optional):
  • clear?: boolean – If true (default), submitted form values will be cleared on error. Set to false to preserve user input after validation or middleware failure.

Return Type

Each server action returns a Response object:

export type Response<S extends ZodSchema, R = object> = {
ok: boolean;
message?: string | { title: string; description: string };
errors?: { [K in keyof z.infer<S>]?: string[] };
values?: Partial<z.infer<S>>;
response?: R;
};

Behavior

  • If ok: true, the action was successful. You may optionally return a response object with any type-safe data.
  • If ok: false, the response may contain:
  • A general message (string or object with title/description)
  • errors for field-level validation (from Zod)
  • values containing submitted form data, unless clear: true (default) was applied

Examples

Custom Response

Return structured data when the action succeeds:

export const signIn = createServerAction<typeof schema, { url: string }>(
schema,
async (values) => {
return { ok: true, response: { url: "https://example.com/dashboard" } };
},
);

The response property is strongly typed as { url: string }.


Empty Response

If you don’t need to return additional data:

export const signIn = createServerAction<typeof schema>(
schema,
async (values) => {
return { ok: true };
},
);

Form-Level Error

Return a general message when submission fails:

export const signIn = createServerAction<typeof schema>(
schema,
async (values) => {
return { ok: false, message: "Invalid credentials" };
},
);

Preserve Form Values on Error

Use clear: false to keep the form populated after an error:

export const signIn = createServerAction<typeof schema>(
schema,
async () => {
return { ok: false, message: "Invalid credentials" };
},
{ clear: false }
);

By default, form values are cleared when an error occurs. This helps reset the form unless you explicitly disable it.


Middleware Handling

If you've defined a global middleware in createClient, and it returns a message:

middleware: async () => {
return { message: "Unauthorized access" };
}

Then this message will be returned by any server action, and the handler won't be executed:

{
ok: false,
message: "Unauthorized access",
values: {} // or original values if clear: false
}