Skip to content

Actions API Reference

Added in: astro@4.15.0

Actions help you build a type-safe backend you can call from client code and HTML forms. All utilities to define and call actions are exposed by the astro:actions module. For examples and usage instructions, see the Actions guide.

import {
ACTION_QUERY_PARAMS,
ActionError,
actions,
defineAction,
getActionContext,
getActionPath,
isActionError,
isInputError,
} from 'astro:actions';

Type: ({ accept, input, handler }) => ActionClient

A utility to define new actions in the src/actions/index.ts file. This accepts a handler() function containing the server logic to run, and an optional input property to validate input parameters at runtime.

src/actions/index.ts
import { defineAction } from 'astro:actions';
import { z } from 'astro:schema';
export const server = {
getGreeting: defineAction({
input: z.object({
name: z.string(),
}),
handler: async (input, context) => {
return `Hello, ${input.name}!`
}
})
}

Type: (input: TInputSchema, context: ActionAPIContext) => TOutput | Promise<TOutput>

A required function containing the server logic to run when the action is called. Data returned from the handler() is automatically serialized and sent to the caller.

The handler() is called with user input as its first argument. If an input validator is set, the user input will be validated before being passed to the handler. The second argument is a subset of Astro’s context object.

Return values are parsed using the devalue library. This supports JSON values and instances of Date(), Map(), Set(), and URL().

Type: ZodType | undefined

An optional property that accepts a Zod validator (e.g. Zod object, Zod discriminated union) to validate handler inputs at runtime. If the action fails to validate, a BAD_REQUEST error is returned and the handler is not called.

If input is omitted, the handler will receive an input of type unknown for JSON requests and type FormData for form requests.

Type: "form" | "json"
Default: json

Defines the format expected by an action:

  • Use form when your action accepts FormData.
  • Use json, the default, for all other cases.

When your action accepts form inputs, the z.object() validator will automatically parse FormData to a typed object. All Zod validators are supported to validate your inputs.

Learn about using validators with form inputs in the Actions guide, including example usage and special input handling.

Type: Record<string, ActionClient>

An object containing all your actions with the action name as key associated to a function to call this action.

src/pages/index.astro
---
---
<script>
import { actions } from 'astro:actions';
async () => {
const { data, error } = await actions.myAction({ /* ... */ });
}
</script>

In order for Astro to recognize this property, you may need to restart the dev server or run the astro sync command (s + enter).

Type: (error?: unknown) => boolean

A utility used to check whether an ActionError is an input validation error. When the input validator is a z.object(), input errors include a fields object with error messages grouped by name.

See the form input errors guide for more on using isInputError().

Type: (error?: unknown) => boolean

A utility to check whether your action raised an ActionError within the handler property. This is useful when narrowing the type of a generic error.

src/pages/index.astro
---
---
<script>
import { isActionError, actions } from 'astro:actions';
async () => {
const { data, error } = await actions.myAction({ /* ... */ });
if (isActionError(error)) {
// Handle action-specific errors
console.log(error.code);
}
}
</script>

The ActionError() constructor is used to create errors thrown by an action handler. This accepts a code property describing the error that occurred (example: "UNAUTHORIZED"), and an optional message property with further details.

The following example creates a new ActionError when the user is not logged in:

src/actions/index.ts
import { defineAction, ActionError } from "astro:actions";
export const server = {
getUserOrThrow: defineAction({
accept: 'form',
handler: async (_, { locals }) => {
if (locals.user?.name !== 'florian') {
throw new ActionError({
code: 'UNAUTHORIZED',
message: 'Not logged in',
});
}
return locals.user;
},
}),
}

You can also use ActionError to narrow the error type when handling the results of an action:

src/pages/index.astro
---
---
<script>
import { ActionError, actions } from 'astro:actions';
async () => {
const { data, error } = await actions.myAction({ /* ... */ });
if (error instanceof ActionError) {
// Handle action-specific errors
console.log(error.code);
}
}
</script>

Type: ActionErrorCode

Defines a human-readable version of an HTTP status code.

Type: string

An optional property to describe the error (e.g. “User must be logged in.”).

Type: string

An optional property to pass the stack trace.

Type: (context: APIContext) => AstroActionContext

Added in: astro@5.0.0

A function called from your middleware handler to retrieve information about inbound action requests. This returns an action object with information about the request, a deserializeActionResult() method, and the setActionResult() and serializeActionResult() functions to programmatically set the value returned by Astro.getActionResult().

getActionContext() lets you programmatically get and set action results using middleware, allowing you to persist action results from HTML forms, gate action requests with added security checks, and more.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
return next();
});

Type: { calledFrom: “rpc” | “form”; name: string; handler: () => Promise<SafeResult>; } | undefined

An object containing information about an inbound action request. It is available from getActionContext(), and provides the action name, handler, and whether the action was called from a client-side RPC function (e.g. actions.newsletter()) or an HTML form action.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'rpc' && action.name.startsWith('private')) {
// Check for a valid session token
}
// ...
});

Type: "rpc" | "form"

Whether an action was called using an RPC function or an HTML form action.

Type: string

The name of the action. Useful to track the source of an action result during a redirect.

Type: () => Promise<SafeResult>

A method to programmatically call an action to get the result.

Type: (actionName: string, actionResult: SerializedActionResult) => void

A function to programmatically set the value returned by Astro.getActionResult() in middleware. It is passed the action name and an action result serialized by serializeActionResult(). Calling this function from middleware will disable Astro’s own action result handling.

This is useful when calling actions from an HTML form to persist and load results from a session.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
// ... handle the action result
setActionResult(action.name, serializeActionResult(result));
}
return next();
});
See the advanced sessions guide for a sample implementation using Netlify Blob.

Type: (res: SafeResult) => SerializedActionResult

Serializes an action result to JSON for persistence. This is required to properly handle non-JSON return values like Map or Date as well as the ActionError object.

Call this function when serializing an action result to be passed to setActionResult():

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action) {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
// ...
});

Type: (res: SerializedActionResult) => SafeResult

Reverses the effect of serializeActionResult() and returns an action result to its original state. This is useful to access the data and error objects on a serialized action result.

Type: (action: ActionClient) => string

Added in: astro@5.1.0

A utility that accepts an action and returns a URL path so you can execute an action call as a fetch() operation directly. This allows you to provide details such as custom headers when you call your action. Then, you can handle the custom-formatted returned data as needed, just as if you had called an action directly.

This example shows how to call a defined like action passing the Authorization header and the keepalive option:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
await fetch(getActionPath(actions.like), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({ id: 'YOUR_ID' }),
keepalive: true
})
</script>

This example shows how to call the same like action using the sendBeacon API:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon(
getActionPath(actions.like),
new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
type: 'application/json'
})
)
</script>

Type: { actionName: string, actionPayload: string }

An object containing the query parameter names used internally by Astro when handling form action submissions.

When you submit a form using an action, the following query parameters are added to the URL to track the action call:

  • actionName - The query parameter that contains the name of the action being called
  • actionPayload - The query parameter that contains the serialized form data

This constant can be useful when you need to clean up URLs after a form submission. For example, you might want to remove action-related query parameters during a redirect:

src/pages/api/contact.ts
import type { APIRoute } from "astro";
import { ACTION_QUERY_PARAMS } from 'astro:actions'
export const GET: APIRoute = ({ params, request }) => {
const link = request.url.searchParams;
link.delete(ACTION_QUERY_PARAMS.actionName);
link.delete(ACTION_QUERY_PARAMS.actionPayload);
return redirect(link, 303);
};
import type {
ActionAPIContext,
ActionClient,
ActionErrorCode,
ActionReturnType,
SafeResult,
} from 'astro:actions';

A subset of the Astro context object. The following properties are not available: callAction, getActionResult, props, and redirect.

Types:

  • (input?: any) => Promise<SafeResult>
  • { queryString?: string; orThrow: (input?: any) => Promise<Awaited<TOutput>>; }

Represents an action to be called on the client. You can use it as a function that accepts input data and returns a Promise with a SafeResult object containing the action result or validation errors.

The following example shows how you can provide error handling with an if statement when incrementing the like count fails:

src/pages/posts/post-1.astro
---
---
<!-- your template -->
<script>
import { actions } from 'astro:actions';
const post = document.querySelector('article');
const button = document.querySelector('button');
button?.addEventListener('click', async () => {
const { data: updatedLikes, error } = await actions.likePost({ postId: post?.id });
if (error) {
/* handle errors */
}
})
</script>

Alternatively, you can use it as an object giving you access to the queryString and an alternative orThrow() method.

Type: string

A string representation of the action that can be used to construct form action URLs. This can be useful when your form component is used in multiple places but you need to redirect to a different URL on submit.

The following example uses queryString to construct a URL that will be passed to the form action attribute through a custom prop:

src/pages/postal-service.astro
---
import { actions } from 'astro:actions';
import FeedbackForm from "../components/FeedbackForm.astro";
const feedbackUrl = new URL('/feedback', Astro.url);
feedbackUrl.search = actions.myAction.queryString;
---
<FeedbackForm sendTo={feedbackUrl.pathname} />

Type: (input?: any) => Promise<Awaited<TOutput>>

A method that throws an error on failure instead of returning the errors. This is useful when you want exceptions rather than error handling.

The following example uses orThrow() to skip error handling when incrementing the like count fails:

src/pages/posts/post-1.astro
---
---
<!-- your template -->
<script>
import { actions } from 'astro:actions';
const post = document.querySelector('article');
const button = document.querySelector('button');
button?.addEventListener('click', async () => {
const updatedLikes = await actions.likePost.orThrow({ postId: post?.id });
})
</script>

Type: string

A union type of standard HTTP status codes defined by IANA using the human-readable versions as uppercase strings separated by an underscore (e.g. BAD_REQUEST or PAYLOAD_TOO_LARGE).

Type: Awaited<ReturnType<ActionHandler>>

A utility type that extracts the output type from an action handler. This unwraps both the Promise (if the handler is async) and the ReturnType to give you the actual output type. This can be useful if you need to reference an action’s output type in your own type definitions.

The following example uses ActionReturnType to retrieve the expected output type for an action named contact:

src/components/Form.astro
---
import { actions, ActionReturnType } from 'astro:actions';
type ContactResult = ActionReturnType<typeof actions.contact>;
---

Type: { data: TOutput, error: undefined } | { data: undefined, error: ActionError }

Represents the result of an action call:

  • on success, data contains the output of the action and error is undefined.
  • on failure, error contains an ActionError with validation errors or runtime errors, and data is undefined.
Contribute Community Sponsor