GuideEdit this page

Server functions

Server functions are async functions that can be called from the client-side. You don't have to implement API endpoints for these functions to be callable as the client can call these functions like a direct reference to the function itself. Server functions are usable on forms, buttons, submit inputs, and as props to client components. React and the framework will manage calling these functions on the server-side.

You can expose any "use server"; marked function as a server function. Server functions can be called from the client using the action prop on a <form> element, formAction on a <button> or <input> element, or from a client component passing down the server function function as a prop to the client component.

If you use TypeScript, all of your server functions are type-safe and you will get type errors if you pass the wrong parameters to a server function or if you try to access a property on the response object that doesn't exist.

You can define server functions inline in your components as any other event handler in a React component.

export default function App() {
  async function action() {
    "use server";
    console.log("Server function called!");
  }

  return (
    <form action={action}>
      <button type="submit">Submit</button>
    </form>
  );
}

Progressive enhancement: if you have JavaScript enabled, the server function will be called using the fetch API and the response will be used to update the DOM in a React transition. If you don't have JavaScript enabled, the server function will be called using a regular HTTP request.

You can even define your server functions inline your JSX.

export default function App() {
  return (
    <form
      action={async () => {
        "use server";
        console.log("Server function called!");
      }}
    >
      <button type="submit">Submit</button>
    </form>
  );
}

Server functions are able to access all variables in scope, including references to props and any variables available in the scope of the server function function from the last render of the component as server function functions are mapped on each render of the server component.

If you want to keep your server functions in separate modules, you can do so by using the "use server"; pragma at the top of your module. All exported functions from a server function module will be usable as server functions.

"use server";

export async function action() {
  console.log("Server function called!");
}

You will get all form data as an object as the first parameter to your server function function.

export default function App() {
  async function action(formData) {
    "use server";
    console.log(`Server function called by ${formData.get("name")}!`);
  }

  return (
    <form action={action}>
      Your name: <input name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}
import { useActionState } from "@lazarv/react-server/router";

export default function App() {
  async function action(formData) {
    "use server";
    console.log(`Server function called by ${formData.get("name")}!`);
  }

  const { error } = useActionState(action);

  return (
    <form action={action}>
      Your name: <input name="name" />
      <button type="submit">Submit</button>
      {error && <p>{error.message}</p>}
    </form>
  );
}

To access the action state, you can use the useActionState hook. The useActionState hook takes the server function function as the first parameter and returns an object with the following properties:

You can also pass server function function references to client components as props and call them from the client component as any other async function.

"use client";

export default function MyClientComponent({ action }) {
  const handleClick = () => {
    action({ name: "John" });
  };

  return <button onClick={handleClick}>Click me!</button>;
}
import MyClientComponent from "./MyClientComponent";

export default function App() {
  async function action({ name }) {
    "use server";
    console.log(`Server function called by ${name}!`);
  }

  return (
    <div>
      <MyClientComponent action={action} />
    </div>
  );
}

Server functions called from client components can return data to the client component directly. This can be useful if you want to display a message to the user after the server function has been completed or if you want to display an error message if the server function failed.

"use client";

export default function MyClientComponent({ action }) {
  const [response, setResponse] = useState(null);

  const handleClick = async () => {
    const response = await action({ name: "John" });
    setResponse(response);
  };

  return (
    <>
      <button onClick={handleClick}>Click me!</button>
      {response && <p>{response.message}</p>}
    </>
  );
}
import MyClientComponent from "./MyClientComponent";

export default function App() {
  async function action({ name }) {
    "use server";
    console.log(`Server function called by ${name}!`);
    return { message: `Hello ${name}!` };
  }

  return (
    <div>
      <MyClientComponent action={action} />
    </div>
  );
}