docs / Language

Client Boundary & Islands

Server-first rendering, the client island modifier, {#client}/{#server} blocks, and which blocks a component kind may use.

Vesk is server-first by default: components render to HTML on the server, and interactivity is attached on the client through hydration. The `client` keyword and `{#client}`/`{#server}` blocks define that boundary explicitly.

Islands: the client keyword

app/components/Clock.vsk
										
											component Clock() client {
  let &[now] = track(new Date());
  effect(() => { /* interval etc. */ });
  <time>{now.toLocaleTimeString()}</time>
}
										
									
  • Marking a component `client` makes it an island: it renders on both server and client.
  • The modifier goes after the params (`component X() client`) or directly after `component`.
  • `client` composes with `export` and `async`: `export component X() client`.
  • Event-handler attributes (`on*`) are excluded from the SSR HTML entirely — the server carries the markup, the client bundle attaches behavior.

{#client} / {#server} blocks

Component kind {#server} {#client}
Server component (default) allowed error (clientBlockInServer)
client island error (serverBlockInClient) allowed
app/components/Clock.vsk
										
											component Clock() client {
  let &[now] = track(new Date());
  effect(() => { /* interval etc. */ });
  <time>{now.toLocaleTimeString()}</time>
}
										
									

`{#server}` blocks render in SSR and are stripped from the client bundle; `{#client}` blocks are stripped from SSR and render on the client. The `#server { ... }` / `#client { ... }` prefix forms parse to the identical VeskBlock node, and blocks nest and accept full statement-mode bodies.

What ships to the client

A module produces a client bundle when any component is a `client` island or has a non-static body. A module where every component is fully static and non-client compiles to an empty client bundle.