What Causes This Error?
This error occurs when you try to use Astro Actions without configuring server-side rendering (SSR) output. Actions require a server to execute and can’t work with static site generation.
The Problem
// astro.config.mjs
export default defineConfig({
// output: 'static' (default) - no server!
});
// src/actions/index.ts
import { defineAction, z } from 'astro:actions';
export const server = {
// ❌ Actions require server output
subscribe: defineAction({
input: z.object({ email: z.string().email() }),
handler: async ({ email }) => {
// Handle subscription
},
}),
};
The Fix
Enable Server Output
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server', // ✅ Enable SSR
adapter: node({
mode: 'standalone',
}),
});
Common Scenarios
Hybrid Mode (Recommended)
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'hybrid', // Static by default, SSR when needed
adapter: vercel(),
});
---
// Pages are static unless prerender is false
export const prerender = false; // This page uses SSR
---
Basic Action Setup
// src/actions/index.ts
import { defineAction, z } from 'astro:actions';
export const server = {
newsletter: defineAction({
input: z.object({
email: z.string().email(),
name: z.string().optional(),
}),
handler: async ({ email, name }) => {
// Store in database, send to API, etc.
await saveSubscriber(email, name);
return { success: true };
},
}),
};
Calling Actions from Client
---
// src/pages/subscribe.astro
export const prerender = false;
---
<html>
<body>
<form id="subscribe-form">
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</form>
<script>
import { actions } from 'astro:actions';
document.getElementById('subscribe-form')
?.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const result = await actions.newsletter({
email: formData.get('email'),
});
if (result.data?.success) {
alert('Subscribed!');
}
});
</script>
</body>
</html>
Different Adapters
// Vercel
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'server',
adapter: vercel(),
});
// Netlify
import netlify from '@astrojs/netlify';
export default defineConfig({
output: 'server',
adapter: netlify(),
});
// Cloudflare
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});
// Node.js
import node from '@astrojs/node';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});
Form Actions (No JavaScript)
---
import { actions } from 'astro:actions';
export const prerender = false;
// Handle form submission on server
const result = Astro.getActionResult(actions.newsletter);
---
<form method="POST" action={actions.newsletter}>
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</form>
{result?.error && <p>Error: {result.error.message}</p>}
{result?.data?.success && <p>Subscribed successfully!</p>}
Check Output Mode
// Verify your output setting
export default defineConfig({
output: 'server', // Required for actions
// or
output: 'hybrid', // Also works
// NOT: output: 'static' (default)
});
Quick Checklist
- Set
output: 'server'oroutput: 'hybrid' - Install and configure an SSR adapter
- Define actions in
src/actions/index.ts - Use
prerender: falsefor pages calling actions - Import actions from
astro:actions