Islands and Rendering
1. What is the islands architecture, and what does Astro ship to the browser by default?
Astro renders every component to HTML on the server or at build time and ships no component JavaScript unless you mark a component as an island.
An island is a framework component (React, Preact, Svelte, Vue, Solid) with a client:* directive; Astro renders its HTML first, then loads that component's code and hydrates only that subtree.
A strong candidate separates the two kinds of components. .astro components never hydrate: their frontmatter runs only on the server, and any interactivity goes in a <script> tag that Astro bundles and processes.
Framework components without a directive render to static HTML and send zero bytes of their own code. A weak answer describes islands as "lazy loading" and misses that the default is no JavaScript at all.
2. Walk through the client directives. Which would you use for a header search box, a below-the-fold carousel and a mobile-only menu?
Per the directives reference:
client:load hydrates as soon as the page loads. Use it for the search box a user may click first.
client:idle waits for requestIdleCallback, with an optional timeout in milliseconds since 4.15.
client:visible hydrates when an IntersectionObserver sees the element, with an optional rootMargin. Use it for the carousel.
client:media hydrates when a media query matches. Use it for the mobile menu.
client:only skips server rendering and needs the framework name as its value.
<SearchBox client:load />
<Carousel client:visible={{ rootMargin: "200px" }} />
<MobileMenu client:media="(max-width: 50em)" />
<MapWidget client:only="react">
<p slot="fallback">Loading map...</p>
</MapWidget>
Good candidates point out that client:media still renders the menu's HTML on desktop, which may need CSS to hide, and that client:only leaves a hole in the server HTML that the fallback slot should fill to avoid layout shift.
3. What can you pass as props to a hydrated island?
Only values Astro can serialize into the HTML. Astro writes island props into the page so the client can rebuild them, so plain objects, arrays, strings, numbers, dates and similar values work, while functions do not.
A callback prop such as onChange works in server-only rendering and silently fails once the component hydrates.
The fix is to move the interaction into the island: let the island own its state and event handlers, or share state between islands through a small store library or custom events. Senior candidates also watch prop size.
A 300 KB product array passed to client:load is duplicated into the HTML as serialized data and then parsed on the main thread.
4. How do prerendering and on-demand rendering combine in one project?
By default Astro prerenders every route to static HTML.
Add an adapter and you can opt individual pages or endpoints into on-demand rendering with export const prerender = false, or set output: 'server' to flip the default and opt static pages back in with export const prerender = true.
The on-demand rendering guide lists official adapters for Node.js, Netlify, Vercel and Cloudflare.
The deciding question is whether the response depends on the request. Cookies, sessions, headers and query strings need on-demand rendering.
A strong candidate keeps the marketing pages static, renders account pages on demand and uses server islands (question 19) for the parts of a static page that are personal.
5. Where can you set response headers and the status code, and where can you not?
Only at the page or endpoint level, on routes rendered on demand. Astro streams HTML, so by the time a nested component or a layout runs, the headers may already be on the wire.
The docs say features that modify the response headers are available only at the page level, not inside components, including layouts.
---
// src/pages/account.astro
export const prerender = false;
const user = Astro.locals.user;
if (!user) return Astro.redirect('/login');
Astro.response.headers.set('Cache-Control', 'private, no-store');
---
A weak answer puts the redirect in a shared layout and wonders why it fails intermittently. In Astro 7, a candidate who wants CDN caching should also mention Astro.cache.set() (question 22) instead of writing Cache-Control by hand.
6. How do <script> tags behave in an Astro component?
A plain <script> in an .astro file is processed: Astro bundles it as a module, resolves imports, supports TypeScript and deduplicates it, so a component used 20 times on a page ships its script once.
Adding any attribute other than src, or is:inline, opts out of processing and leaves the tag as written.
define:vars is the common surprise. On a <script> it implies is:inline, so the script is no longer bundled and renders once per component instance.
The better pattern for passing server values to a processed script is a data-* attribute that the script reads.
Since Astro 6, scripts and styles render in the order you define them, a behavior that used to sit behind the preserveScriptOrder flag.
7. What does queued rendering change, and when does it matter?
Queued rendering is the rendering engine that became the default in Astro 7, after shipping as experimental.queuedRendering in 6.0.
The 7.0 post reports about 2.4 times faster rendering on expression-dense pages, with less gain on static ones.
The same post reports build times 15% to 61% faster in Astro's benchmarks across the Rust compiler, the Rust Markdown pipeline and the new engine together.
A good answer stays measured: the speedup shows up on large builds with many dynamic expressions, such as a docs site with thousands of pages.
Candidates who have profiled a build should mention astro build --timings, added in 7.4, which breaks build time down by phase, Vite plugin, Markdown, rendering, images and integrations.