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.
Imports from astro:actions
Section titled âImports from astro:actionsâimport { ACTION_QUERY_PARAMS, ActionError, actions, defineAction, getActionContext, getActionPath, isActionError, isInputError, } from 'astro:actions';defineAction()
Section titled âdefineAction()â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.
import { defineAction } from 'astro:actions';import { z } from 'astro/zod';
export const server = { getGreeting: defineAction({ input: z.object({ name: z.string(), }), handler: async (input, context) => { return `Hello, ${input.name}!` } })}handler() property
Section titled âhandler() propertyâ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().
input validator
Section titled âinput validatorâ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.
accept property
Section titled âaccept propertyâType: "form" | "json"
Default: json
Defines the format expected by an action:
- Use
formwhen your action acceptsFormData. - 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.
actions
Section titled âactionsâType: Record<string, ActionClient>
An object containing all your actions with the action name as key associated to a function to call this action.
------
<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).
isInputError()
Section titled âisInputError()â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.
isInputError().
isActionError()
Section titled âisActionError()â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.
------
<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>ActionError
Section titled âActionErrorâ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:
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:
------
<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.
message
Section titled âmessageâ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.
getActionContext()
Section titled âgetActionContext()âType: (context: APIContext) => AstroActionContext
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.
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.
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 } // ...});action.calledFrom
Section titled âaction.calledFromâType: "rpc" | "form"
Whether an action was called using an RPC function or an HTML form action.
action.name
Section titled âaction.nameâType: string
The name of the action. Useful to track the source of an action result during a redirect.
action.handler()
Section titled âaction.handler()âType: () => Promise<SafeResult>
A method to programmatically call an action to get the result.
setActionResult()
Section titled âsetActionResult()â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.
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();});serializeActionResult()
Section titled âserializeActionResult()â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():
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)); } // ...});deserializeActionResult()
Section titled âdeserializeActionResult()â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.
getActionPath()
Section titled âgetActionPath()âType: (action: ActionClient) => string
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:
<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:
<script>import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon( getActionPath(actions.like), new Blob([JSON.stringify({ id: 'YOUR_ID' })], { type: 'application/json' }))</script>ACTION_QUERY_PARAMS
Section titled âACTION_QUERY_PARAMSâ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 calledactionPayload- 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:
import type { APIRoute } from "astro";import { ACTION_QUERY_PARAMS } from "astro:actions";
export const GET: APIRoute = ({ redirect, request }) => { const link = new URL(request.url).searchParams; link.delete(ACTION_QUERY_PARAMS.actionName); link.delete(ACTION_QUERY_PARAMS.actionPayload);
return redirect(link.toString(), 303);};astro:actions types
Section titled âastro:actions typesâimport type { ActionAPIContext, ActionClient, ActionErrorCode, ActionInputSchema, ActionReturnType, SafeResult, } from 'astro:actions';ActionAPIContext
Section titled âActionAPIContextâA subset of the Astro context object. The following properties are not available: callAction, getActionResult, props, and redirect.
ActionClient
Section titled âActionClientâ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:
------
<!-- 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.
ActionClient.queryString
Section titled âActionClient.queryStringâ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:
---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} />ActionClient.orThrow()
Section titled âActionClient.orThrow()â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:
------
<!-- 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>ActionErrorCode
Section titled âActionErrorCodeâ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).
ActionInputSchema
Section titled âActionInputSchemaâType: ZodType
astro@5.16.0
A utility type that automatically infers the TypeScript type of an actionâs input based on its Zod schema. This can be useful to reference an actionâs input validator type as an object in your own type definitions.
Returns never when input validator is omitted.
The following example uses ActionInputSchema on an action named contact to:
- Retrieve the Zod schema type for the input of the action.
- Retrieve the expected input type of the actionâs validator.
---import { actions, type ActionInputSchema } from "astro:actions";import { z } from "astro/zod";
type ContactSchema = ActionInputSchema<typeof actions.contact>;type ContactInput = z.input<ContactSchema>;---ActionReturnType
Section titled âActionReturnTypeâ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:
---import { actions, type ActionReturnType } from "astro:actions";
type ContactResult = ActionReturnType<typeof actions.contact>;---SafeResult
Section titled âSafeResultâType: { data: TOutput, error: undefined } | { data: undefined, error: ActionError }
Represents the result of an action call:
- on success,
datacontains the output of the action anderrorisundefined. - on failure,
errorcontains anActionErrorwith validation errors or runtime errors, anddataisundefined.