# Server Functions

Server Functions let [Client Components](./rendering/components.md#client-components) call async
functions that execute on the server. Form actions also work without JavaScript.

`"use server"` marks a function so the client can call it over the network. The same function is a
**Server Action** when it's passed to a form's `action` prop or called from an action, following
React's terminology. See [React's Server Functions docs](https://react.dev/reference/rsc/server-functions)
for the full model.

## Defining Server Functions

Add `"use server"` at the top of a module to turn all its exports into Server Functions. Every
exported value in that module must be an async function:

```ts
// app/actions.ts
"use server"

export async function createItem(name: string) {
  await db.items.create({ name })
}
```

Or mark a single function inline in a [Server Component](./rendering/components.md#server-components)
and pass it to a Client Component:

```tsx
export default function Page() {
  async function greet(name: string) {
    "use server"
    return `Hello ${name}`
  }

  return <GreetingButton greet={greet} />
}
```

## Calling Server Functions

Call a Server Function from a Client Component like any async function. Rebask sends the call to the
server and resolves with the result:

```tsx
"use client"

import { createItem } from "./actions"

export function NewItemButton({ name }: { name: string }) {
  return <button onClick={() => createItem(name)}>Create</button>
}
```

In Client Components, call Server Functions from event handlers or effects, not during render.

Calling a Server Function from a Server Component runs it in the same process, with no network
request.

## Server Functions with form actions

Pass a Server Function to a form's `action` prop to run it on submit. Because the form submits
natively, this works without JavaScript:

```tsx
"use client"

import { updateName } from "./actions"

export function NameForm() {
  return (
    <form action={updateName}>
      <input name="name" />
      <button type="submit">Save</button>
    </form>
  )
}
```

Use `useActionState` to read the result back into the page:

```tsx
"use client"

import { useActionState } from "react"
import { saveProfile } from "./actions"

export function ProfileForm() {
  const [state, formAction] = useActionState(saveProfile, { error: null })

  return (
    <form action={formAction}>
      <input name="displayName" />
      {state.error ? <p>{state.error}</p> : null}
      <button type="submit">Save</button>
    </form>
  )
}
```

Define the action as `(prevState, formData)`:

```ts
"use server"

export async function saveProfile(_prevState: unknown, formData: FormData) {
  const name = String(formData.get("displayName") ?? "")
  if (!name) return { error: "Name is required" }

  await db.profiles.update(name)
  return { error: null }
}
```

Bind arguments that aren't part of the form:

```tsx
<form action={updateItem.bind(null, itemId)}>
```

Bound arguments come before the action's other arguments. The submitted `FormData` is always last.

## Arguments

When called from a Client Component, arguments cross the network and must be serializable. Strings,
numbers, booleans, `null`, `undefined`, arrays, nested objects, `Date`, `Map`, `Set`, typed arrays,
`ArrayBuffer`, `Blob`, `FormData` (including `File` uploads), and React elements are supported. Custom
class instances and functions are not.

Form submissions pass the submitted `FormData` as the final argument:

```ts
"use server"

export async function updateItem(itemId: number, formData: FormData) {
  const name = String(formData.get("name"))
  await db.items.update(itemId, name)
}
```

## Request APIs

[`headers()`](./server-runtime-apis.md#headers) and [`cookies()`](./server-runtime-apis.md#cookies)
are available inside a Server Function. Write response cookies with `await cookies()`:

```ts
"use server"

import { cookies } from "@rebask/core/cookies"

export async function login() {
  const store = await cookies()
  store.set("session", token, { httpOnly: true, path: "/" })
}
```

Cookie writes apply even if the function throws.

[`routeParams()`](./server-runtime-apis.md#routeparams) and
[`searchParam()`](./server-runtime-apis.md#searchparamname) aren't available, because a function isn't
tied to a route.

## Return values and errors

Return values sent to a Client Component must be serializable, and React elements are supported.
Return a value for expected failures:

```ts
"use server"

export async function createProfile(formData: FormData) {
  const name = String(formData.get("name") ?? "")

  if (!name) {
    return { error: "Name is required" }
  }

  await db.profiles.create({ name })
}
```

Throwing is for unexpected errors. When you call a Server Function from a Client Component, the
function rejects in the browser, so handle it where you call it:

```tsx
<button
  onClick={async () => {
    try {
      await createItem(name)
    } catch (error) {
      setError(getMessage(error))
    }
  }}
>
  Create
</button>
```

Errors thrown inside the function reject with a plain `Error` rebuilt from the serialized response,
so custom error classes don't survive. In development the message is the original one. In production
React replaces it with a minified error code, such as `Minified React error #441`, and Rebask logs
the original message on the server.

A throw in a no-JS form submission renders the framework
[error page](./error-handling.md).

## Mutations

Server Functions do not refresh client route data. After a mutation, refresh the current client
segment with [`router.revalidate()`](./routing/navigations.md#userouter-routerrevalidate). If the
mutation invalidates tagged server data, also call [`revalidateTag()`](./caching/cache-lifetimes.md#revalidatetag).

## Security

Rebask checks the `Origin` header against the request host before running a Server Function.
Same-origin requests pass. Cross-origin requests are rejected unless the origin host matches
[`serverFunctions.allowedOrigins`](./configuration.md#rebaskconfigts-serverfunctions).

`allowedOrigins` accepts exact hosts and wildcard patterns: `*.example.com` matches one subdomain
level, and `**.example.com` matches any depth. Behind a proxy, add the forwarded hostname to
`serverFunctions.allowedForwardedHosts` so `X-Forwarded-Host` is trusted for the comparison.

Request bodies are limited to 1 MB by default. Larger requests get a `413`. Set
[`bodySizeLimit`](./configuration.md#rebaskconfigts-serverfunctions) in bytes to change it.
