Diagnosing Astro Client-Directive Hydration Failures
An Astro island with a client directive renders but never becomes interactive. Use DevTools, the console, and build comparisons to find and fix the cause.
01 Oct 2026, 03:59 UTC

The problem: an island that never wakes up
You add client:load, client:visible, client:idle, or client:only to an Astro component. The page loads, but the component stays static: buttons do not respond, forms do not submit, and state does not update. In Astro, an interactive component is called an island, and hydration is the process of attaching client-side JavaScript to server-rendered HTML so the component becomes interactive.
Most of these failures are caused by a missing or misplaced directive, a missing framework integration, or a markup difference between the server and the browser. They usually appear in DevTools and the browser console before they require an issue report.
Recognizable condition and likely causes
| Condition | Likely cause | Where it appears |
|---|---|---|
| Component renders HTML but no client-side interactivity | Directive missing, misspelled, or placed on a native HTML element | DevTools Elements panel |
| Console error about missing framework runtime | Framework integration not installed or not listed in astro.config.mjs | Browser Console |
| Hydration mismatch warning or flickering content | Server markup differs from client hydrate markup | Browser Console |
Works in astro dev but fails after astro build | Build-mode difference between static and SSR output | Terminal and preview server |
client:only island is absent from initial HTML | Expected behavior; client:only omits server HTML for that island | View page source |
Ordered checks
- Confirm the component is an island. Open the page in a browser, right-click the component, and inspect it. Look for the
astro-islandattribute on the element or its wrapper. If the attribute is missing, Astro did not treat the component as a hydration boundary. - Verify directive spelling and placement. Client directives belong on a framework component such as React, Vue, Svelte, or Solid, not on a native HTML element such as
<button>or<div>. Check for typos likeclient:loadsorclient-load. - Check the browser console. Look for hydration mismatch warnings, missing framework errors, or silent failures. Extensions, rendered dates, and random values can also cause mismatch warnings, so do not treat every warning as an Astro configuration bug.
- Confirm the framework integration. Open
astro.config.mjsand verify the integration is installed and listed in theintegrationsarray. A React component, for example, needs the Astro React integration. - Compare dev and build behavior. Run
astro dev, then runastro buildfollowed byastro preview. If the component works in dev but not in preview, the issue is likely build-mode or SSR specific.
Fixes tied to findings
Directive on a native element
Move the directive onto the framework component wrapper.
<!-- Not effective on a native element -->
<button client:load>Click me</button>
<!-- Effective on a framework component -->
import Button from '../components/Button.jsx';
<Button client:load>Click me</Button>
Missing framework integration
Install the integration for your framework and add it to astro.config.mjs. Replace @astrojs/react with the integration matching your framework.
# Run in the project root. No special permissions are required.
# Placeholder: substitute the integration for your framework.
npm install @astrojs/react react react-dom
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
export default defineConfig({
integrations: [react()],
});
Risk: after adding an integration, restart the dev server so the configuration is picked up.
Server and client markup mismatch
Ensure the component renders the same initial HTML on the server and the client. Avoid dates, random values, or browser-only APIs in the render path unless they are guarded or identical on both sides. If the content does not need server HTML, use client:only to skip server rendering for that island.
Risk: client:only omits server HTML, which can affect initial paint and SEO-sensitive content. Use it only when the component is not critical for the first meaningful paint.
Hydrate below the fold lazily
If an interactive component is below the fold, prefer client:visible or client:idle over client:load to avoid blocking initial hydration.
Escalation criteria
Escalate to the Astro project only when all of the following are true:
- A clean build with current dependencies still fails.
- A minimal reproduction exhibits the same behavior in both static output and
astro build --ssroutput. - You can share the Astro major version, adapter versions, and browser console output.
Create a minimal repository and report it to the Astro project with those details.
Limitations and how to verify the result
Client-directive semantics can change between Astro major releases. Check astro --version and consult the documentation for your installed major version before applying behavior from an older guide.
To verify a fix:
- Run
astro devfrom the project root. - Open the page, inspect the component, and confirm the
astro-islandattribute and expected hydration script are present. - Interact with the component to confirm it responds.
- Run
astro buildandastro preview, then repeat the interaction check. - Run
astro build --ssrand preview that output to confirm the issue is not static-only or SSR-only.
If the component is interactive in both dev and preview after the change, the diagnostic is complete.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.