komal.nakrani
Browse Themes
ThemesCategoriesDocsBlogTips & Tricks
Server Rendering••By Komal Nakrani

Fix: Actions Must Be Used With Server Output in Astro

Astro Actions need a server. Fix 'Actions must be used with server output' by adding an adapter and an on-demand route, or use a form service on a static site.

#Astro#Errors#Actions#Adapters

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} with Astro.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.