Skip to content

Data & state

Data & remote functions

All six Kit remote primitives work inside islands: query, command, form, and more.

On this page

Islands are real Svelte components (see the last chapter), so Kit’s remote functions work inside them unchanged. All six primitives (query, query.batch, query.live, command, form, and prerender) run in an island exactly as they do in a Kit page.

When to use

Remote functions are how an island talks to the server: read data (query), mutate it (command / form), or stream it (query.live). Use them whenever an island needs server data or has to persist a change. They replace the fetch-and-endpoint boilerplate you would otherwise write, and the server validates every call.

<script>
  import { greeting } from './hello.remote';
  const who = await greeting();
</script>

<p>{who}</p>

SSR query results are seeded into the client cache, so an island that reads a query during server render does not refetch on hydrate in production. (Dev degrades to a refetch; see the note below.)

Try it

This counter is a client island reading a query and mutating through two commands. The value lives on the server; every button is a real round-trip, then a .refresh() re-reads it. It is shared state: open this page in a second tab and watch both move.

server count

Every click is a real round-trip. Open this page in two tabs — the count is shared.

let count = 3;
export const getCount = query(async () => count);
export const bump = command(async () => (count += 1));

Forms and commands

form() and command() POST to their endpoints and work from inside an island. On success, form() runs Kit’s invalidateAll, which ogygia treats as a soft seed refresh: it re-fetches the current page, merges <head>, and refreshes the in-place data seeds: no view transition, no body swap, no island remount, no live-query clear.

<script>
  import { addEntry } from './guestbook.remote';
</script>

<form {...addEntry}>
  <input name="msg" />
  <button>Sign</button>
</form>

If an island needs a query to update after a mutation, call .refresh() on it, or pair submit().updates(query) with server-side requested(query).refreshAll(). updates alone does not populate the response.

Mutation guards

Writing to a captured host variable from island markup is a mistake: the value is a serialized snapshot, not live state. In dev, ogygia wraps every snapshot in a deep proxy that console.warns (naming the offending prop path) when you mutate one. The write still applies (it is only a warning), so treat it as the signal to move that state into the island.

Dev is not prod

In dev, SSR query seeding degrades to a refetch, and the mutation proxy only runs in dev. Verify data flows against a production build.

Do / don’t

  • Do call .refresh() (or submit().updates(q) + server requested(q).refreshAll()) when a mutation should update a query. updates alone does not populate the response.
  • Do test data flows against a production build, since dev seeding and the mutation guard behave differently.
  • Don’t mutate a captured host prop from island markup. It is a serialized snapshot; move mutable state inside the island.

Next chapter: collections turn your content into typed entries.