Astro shows “Actions must be used with server output” when the project defines actions in src/actions/ but has nowhere to run them. The message: “A server is required to create callable backend functions.” Actions are server code, so you need an adapter, and the page that submits a form to an action needs on-demand rendering. The hint sums it up: “Add an adapter and enable on-demand rendering.”
Key Takeaways
- Actions require an adapter:
npx astro add node | cloudflare | netlify | vercel.- A page using an HTML form
action={actions.x}withAstro.getActionResult()must be on-demand.- Calling an action from client JavaScript works from static pages once an adapter exists.
- Fully static sites can post forms to a third-party endpoint instead.
Fix 1: add an adapter
npx astro add node # or cloudflare, netlify, vercel
Keep output: 'static' (the default) if most pages are static.
Fix 2: make the form page on-demand
A plain HTML form posting to an action is handled during the page request, so that page renders on demand:
---
// src/pages/contact.astro
export const prerender = false;
import { actions } from 'astro:actions';
const result = Astro.getActionResult(actions.contact);
---
{result?.data && <p>Thanks, we'll be in touch.</p>}
<form method="POST" action={actions.contact}>
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<button>Send</button>
</form>
Or call the action from the browser
If you’d rather keep the page static, call the action from a script. Actions still need the adapter, but the page doesn’t:
<form id="contact">
<input name="email" type="email" required />
<button>Send</button>
<p role="status" aria-live="polite"></p>
</form>
<script>
import { actions } from 'astro:actions';
const form = document.querySelector<HTMLFormElement>('#contact')!;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const { error } = await actions.contact(new FormData(form));
form.querySelector('[role=status]')!.textContent = error ? error.message : 'Sent.';
});
</script>
Option 3: no server at all
If the site must stay fully static (GitHub Pages, plain object storage), delete src/actions/ and post forms to a hosted form endpoint or your email provider. The newsletter signup tip shows both the static and action versions side by side.
Calling actions from server code
From a page’s frontmatter, use Astro.callAction() rather than calling the action directly, or you’ll hit Action called from the server without Astro.callAction().
Actions, adapters and on-demand pages are covered in the Astro SSR guide and mixing static and on-demand pages. The Actions guide is the reference.
FAQ
Do actions work on Cloudflare Pages?
Yes, with the @astrojs/cloudflare adapter.
Can I use actions without JavaScript in the browser?
Yes. An HTML form with action={actions.name} on an on-demand page works without client JavaScript.