JavaScriptWeb Development

SvelteKit 2.61: .run() Removed, query.live() Arrives

SvelteKit 2.61.0 is out, and if you’re using remote functions, your code may already be broken. The .run() method is gone — removed from remote queries with no deprecation period. The enhance callback API changed shape. The good news is that the same release ships query.live(), a real-time data subscription primitive that’s been quietly maturing since 2.59. Fix the breakage, get something genuinely useful in return.

What Broke in SvelteKit 2.61.0

Two breaking changes landed in SvelteKit 2.61.0. Both affect remote functions, which are still experimental — opt in via kit.experimental.remoteFunctions in svelte.config.js. If you’re not using remote functions yet, skip ahead to the query.live() section. If you are, read carefully.

The .run() Removal

Remote queries previously required .run() when called imperatively — inside event handlers, async callbacks, or module scope. That method is now gone. The query function itself is the executor.

// Before (broken in 2.61.0)
await query.run();

// After
await query();

That’s the whole migration. Find every .run() call and remove it. Cache deduplication is now shared across reactive and non-reactive consumers, which was the actual reason for the removal — the old API created a distinction that didn’t need to exist.

Enhance Callbacks Changed Shape

The second breaking change hits progressive enhancement. enhance callbacks used to receive a destructured object: { form, data, submit }. They now receive a copy of the remote form function instance directly, which exposes a .submit() method you can call programmatically.

This is strictly better — you can pass the form instance around, store it, call it from anywhere. But the destructuring pattern that worked before will silently do nothing. Update your enhance callbacks or they’ll break without an obvious error.

Also in 2.60.0: submit and hidden remote form fields now accept booleans and numbers directly, instead of requiring string coercion. Small change, but it removes an annoying friction point.

query.live() — Real-Time Without the Boilerplate

Here’s the payoff. query.live() creates a long-lived remote query that pushes updates to subscribers without manual polling or a separate WebSocket setup. The callback is an async generator; the client treats the query as an async-iterable and re-renders as new values arrive. You can read about it in the official June 2026 release notes.

// feed.remote.ts
export const liveFeed = query.live(async function* () {
  yield await db.select().from(posts);
  // Yield more values as data changes
});
<!-- Feed.svelte -->
<script>
  import { liveFeed } from './feed.remote.ts';
  const feed = liveFeed();
</script>

{#each feed.current as post}
  <article>{post.title}</article>
{/each}

A few implementation details worth knowing: multiple component instances share a single connection. When no active consumers remain, the stream disconnects and server-side iteration stops — no manual cleanup needed. The query exposes a .connected boolean and a .reconnect() method for handling dropped connections. The initial value is serialized and reused during hydration, so there’s no flash of empty content.

query.live() arrived as experimental in 2.59.0. The async-iterable interface landed in 2.61.0. It’s still experimental, so pin your version — but the API is tightening, not flailing. Check the full changelog for the complete list of changes across 2.59 through 2.61.

What This Means for SvelteKit’s Direction

Remote functions are SvelteKit’s bet that most apps don’t need dedicated API routes. The pitch is straightforward: write a function in .remote.ts, call it from a component, get full type safety and caching without writing a +server.ts file, manually typing the fetch, or keeping request and response shapes in sync by hand. The remote functions documentation covers the full API across query, form, command, and prerender variants.

The community response has been blunt. One developer put it this way: “remote functions are awesome and will be extremely hard to ever go back to.” The complaints are mostly about breaking changes during the experimental phase — which is legitimate — but the direction itself isn’t controversial. The API boilerplate that Next.js normalized is avoidable, and SvelteKit is proving it.

query.live() extends this logic into real-time territory. WebSocket boilerplate is even more tedious than REST boilerplate. If SvelteKit can make live data feel as natural as a static query, that’s a structural advantage that compounds over time.

Quick Takeaways

  • SvelteKit 2.61.0 removes .run() from remote queries — replace await query.run() with await query()
  • Enhance callbacks now receive a form instance copy instead of { form, data, submit } — update destructuring patterns
  • query.live() enables real-time server-push data via async generators — no WebSocket setup required
  • Remote form fields now accept booleans and numbers directly (since 2.60.0)
  • SvelteKit now warns at dev time when remote form validation issues are never read

Remote functions are still experimental. Pin your SvelteKit version if you’re using them in production. But the breaking changes in 2.61 are the kind that happen when an API is maturing — not the kind that happen when a team is uncertain about direction. The direction is clear.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:JavaScript