Hook Server Flag Ignored

Error: Hook "X" (module "Y") sets "server: true", but this hook classifies as a UI/action zone contribution, which has no server/client split.

The Problem

A hook entry sets { server: true } under a hook name that classifies as a UI/action zone contribution — any launcher:-prefixed or :action-suffixed hook name, regardless of entry type (see hook-kind-mismatch for the full classification rule).

The Why

server: true excludes a hook entry from the client bundle — but only for logic hooks, compiled into virtual:stnd/hooks, which resolves to a different virtual module for SSR vs. the client build (generateHooksModule({ ssr }) filters server: true entries out of the client version).

UI/action zone contributions compile into virtual:stnd/components instead, which has no SSR/client split at all — it’s the same single module in both contexts, because it’s also read directly by client-bundled code (packages/launcher/launcher.ts for launcher:action, GraftToolbar.svelte for graft:action) that needs the actual function reference to call on click, not just server-rendered output.

Before this check existed, server: true on one of these entries was silently accepted and did nothing — the entry still shipped into the client bundle exactly as if the flag weren’t there. That’s a dangerous kind of silence: a developer marking a handler server: true is very likely doing it because the handler touches something sensitive (a DB call, a secret, server-only auth state), and a no-op safety flag gives false confidence that it’s protected when it isn’t.

The Solution

  1. Remove server: true if this handler is genuinely meant to run client-side (the common case for launcher:action/graft:action — they’re click handlers).
  2. Rename the hook off the launcher:/:action pattern if it must stay server-only. Logic hooks support server: true correctly — see modules for the runHook/runPipeline two-way split.
  3. Move server-only work behind astro:actions instead, if what you actually need is “a client can trigger this, but the sensitive part runs server-side” — that’s what Astro Actions are for, and it’s the pattern this framework’s own billing module already uses (actions: "./actions.ts", unrelated to the hooks: classification this error is about).

Are you absolutely sure?

This action cannot be undone.