Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Asynchronous Svelte#15845

Apr 28, 2025· 44 comments· 166 replies
Discussion options

This is a long document; get yourself a cup of tea.

tl;dr

You can now use theawait keyword in Svelte — in your<script>, inside$derived expressions, and in your markup — by installing theasync branch...

npm i https://pkg.pr.new/svelte@async

...and adding theexperimental.async option to yoursvelte.config.js (or wherever you configure Svelte):

// svelte.config.jsexportdefault{compilerOptions:{experimental:{async:true}},kit:{// ...}};

You can also try things out in theasync playground.

You will find bugs! This is in no way production-ready. The PR that accompanies this discussion is at#15844.

Background

In olden times, we did asynchronous work like fetching data insideonMount or an{#await ...} block. This works but it's quite verbose, and offers no coordination — if two components are both fetching stuff, then they will likely have independently managed error/loading states, often resulting in a janky UI with multiple spinners.

Frameworks like SvelteKit (or Remix or pre-App-Router Next.js, etc) offer an alternative: instead of fetching inside the component, we do our asynchronous workoutside the component, for example inload functions. This typically results in better user experience (we can server-render the data, preload it, and coordinate everything) but it too has problems — prop-drilling, type shenanigans, coarse-grained invalidation, and logic that's hard to delete because it's often not obvious whether something in yourload function is even being used.

In recent years component frameworks have explored a third way: putting asynchronous work back inside components, but in a way that is coordinated:

  • React has a variety of primitives —<Suspense>,startTransition,useTransition,use and React Server Components, that together allow you to manage async updates
  • Solid has acreateResource API that can be used with<Suspense> andstartTransition/useTransition for the same purpose
  • Vue allows you to useawait inside a<script setup> in a component inside a<Suspense> boundary, though this experimental API only works for component creation, not subsequent updates

We believe Svelte's compiler-centric nature offers us a way to have component-level async work with significantly better ergonomics and fewer drawbacks than existing approaches.

Requirements

  • minimal ceremony — we want to just write code, ideally using theawait keyword. Avoid framework-specific APIs and idioms to the extent possible
  • flexibility — it should be possible to use asynchronous values anywhere (in the<script>, inside$derived expressions, in the template, in attributes and component props, in control flow like{#if ...} blocks, or wherever else)
  • parallel by default — since expressions in the template can be safely assumed to be pure, sequentialawait expressions need not result in sequential async work. Similarly, asynchronous work in two sibling components (for example) should happen simultaneously
  • automatic coördination — iffoo changes, andawait bar(foo) is (or will be) visible on the page, any occurrences offoo in the UI should not update untilbar(foo) resolves
  • overlapping updates — a state change that happens while asynchronous work is ongoing should be visible immediately without waiting for the work to complete (unless it results inmore async work)

We also want this to have minimal impact on performance and memory for existing codebases, and to cause little or no breakage for existing apps.

Design

In a nutshell: you can now useawait in three places that will today result in a syntax error:

  • at the top level of a component<script>
  • in a$derived expression
  • in a template expression (i.e. in a component's markup)

We also introduce apending snippet to<svelte:boundary>, which allows you to provide UI whenawait expressions inside the boundary are first resolving. For now,await expressionsmust be inside a boundary with a pending snippet (however deeply nested — for example you might have a single boundary at the very root of your app), though this constraint will likely be relaxed in future.

If state is read inside a$derived or template expression with anawait, changes to that state willnot be reflected in the UI until the expression resolves. For example in a situation like this...

<h1>Weather forecast for {city}</h1><p>{awaitgetWeatherForecast(city)}</p>

...the<h1> will not update until the<p> does. (IfgetWeatherForecast were to fail, it would activate the nearesterror boundary.)

To know if an update is currently pending, you can use$effect.pending():

{#if$effect.pending()}  <p>loading new data...</p>{/if}

Ifunrelated state changes while an update is pending, it will be visible immediately (assuming it doesn't separately cause asynchronous updates).

Use cases

The most obvious use case is loading data (which could be as simple asfetch, but in many cases will likely involve yet-to-be-designed utilities for client-server communication), but others include:

  • demo preloading images to avoid jank (<img alt="..." src={await preload('...')}>)
  • demo lazily importing modules and components as needed
  • demo moving expensive computation to a web worker

Avoiding waterfalls

As much as framework authors like to witter on about rendering performance, the thing that really slows apps down islatency. In some cases you can reduce latency by speeding up your back end, or prefetching content you expect to need, or serving content from somewhere close to the user, but those things aren't always possible. What youcan do is mitigate the effect of latency by minimising the number of round trips between the browser and the server.

Svelte helps by doing as much work as possible in parallel. For example here...

<li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li><li>canteloupes {awaitgetPrice('canteloupe')} each</li>

...the three calls togetPrice will happen simultaneously, even though they appear in sequence. Similarly, the three wise monkeys will do all their async work together:

<WiseMonkeyverb="see" /><WiseMonkeyverb="hear" /><WiseMonkeyverb="speak" />

Not all work can be parallelized. Anyawait expressions inside the<script> run before expressions in the template, and in the sequence you would expect...

// `a` will be calculated and _then_ `b` will be calculatedleta=$derived(awaitfoo(x));letb=$derived(awaitbar(x));

...though note that ifx subsequently updates,a andb will be recomputed in parallel. You can of course avoid the initial waterfall like so:

letaPromise=$derived(foo(x));letbPromise=$derived(bar(x));leta=$derived(awaitaPromise);letb=$derived(awaitbPromise);
A brief digression on 'necessary' waterfalls and server components

Whileunnecessary waterfalls can generally be prevented by pushing async work as far into the 'leaves' of your application as possible, there are alsonecessary waterfalls to contend with. For example, you can't usePromise.all here, because you need to knowartist.id before you can callgetTrackListing:

letartist=$derived(awaitsearch(query));lettracks=$derived(awaitgetTrackListing(artist.id));

It's better if you can do both fetches on the server, near your database. There are two ways to solve this: either anticipate the need for the track listing when you do the search...

let[artist,tracks]=$derived(awaitsearchAndGetTrackListing(query));

...or use a mechanism like React Server Components, where the rendering happens on the server. Option 1 has less-than-ideal ergonomics, though it's basically equivalent to SvelteKit'sload function. Option 2 is optimal from a waterfall prevention perspective, but we feel RSCs have significant trade-offs.

We anticipate that opinionated data-fetching patterns will emerge over time, along with new approaches inspired by RSCs, to solve this problem.


Future work

The work presented so far is the first step of a multi-stage process. While it's useful in its current form, more value will be unlocked with later stages:

Async SSR

Today,server-side rendering is fully synchronous. Because of this, if a<svelte:boundary> with apending snippet is encountered during SSR, thepending snippet will be rendered.

It would be better to render the content instead, but this requires that SSR become an asynchronous operation.

In an ideal world we would also be able to stream the result where appropriate. This is complicated by the fact that you ideally need to know what's in the<head> before you get to the<body>. We have some ideas for how to design this sensibly, but it's not a current priority.

Once we get to this part, it's likely that the requirement forawait expressions to be contained in a<svelte:boundary> will go away.

Forking

In SvelteKit we preload the code and data necessary for a navigation before it even occurs: when you hover over a link, or tap it, we import any modules needed by the route and begin running whicheverload functions need to run. (This behaviour is configurable, of course.)

To make this work in a world where asynchronous work happens inside components, we need to be able topretend that a state change occurred, and do the resulting updates 'off-screen'. The result can either be applied or discarded.

Colloquially, we've been describing this as a 'fork'. You could imagine several unresolved forks coexisting simultaneously until one reality is chosen (by the user clicking on one of several links they've been close to interacting with, for example). Most likely, we'll add an API to Svelte that allows frameworks like SvelteKit (but also particularly ambitious application authors) to enter the multiverse.

This all sounds very complicated, but in reality it's not all that different to how asynchronous updates already work. Nevertheless, it will take some finagling to get right, and in the interests of shipping we haven't included this work in the current PR.

Client-server utilities

Unless we want to createserver endpoints for everything we want tofetch inside a component, we'll need tools for interacting with the server. Those tools will need to consider security, HTTP caching, mutations and invalidation, optimistic UI, batching, streaming, custom serialization, type safety and lots of other things.

We're at the early stages of figuring out what this all looks like, but we're very confident that the foundation we're laying here will allow us to design something really good.

Improving SvelteKit

Anticipating everyone's reaction: no, we're not going to suddenly make you rewrite all your SvelteKit apps. But taking all the other stuff together, a picture starts to emerge: a version of SvelteKit that's athinner layer on top of Svelte. For example, as proud as we are of ourzero-effort type safety, it's something you no longer need if you're fetching data directly inside your component.

Meanwhile the framework internals could potentially get simpler, because we'd be able to rely on common primitives inside Svelte itself. (Today, we can't reuse that much code between the server and client portions of SvelteKit, and we rely a lot on virtual modules and generated code. Some of that is for historical reasons, but some is necessary because anything asynchronous has to happen outside Svelte.)

It seems likely that a lot of interesting new possibilities will open up as a result of this work, and it seems at leastplausible that we'll collectively find ourselves drifting away from primitives likeload. Exactly what this would look like is to be determined, and it's something that we'll figure out together as a community.

Nuances

NostartTransition/useTransition

If you've used React or Solid's suspense implementation, you will have encounteredstartTransition anduseTransition. These functions allows you to update state in such a way that the nearest suspense boundary doesn't show its fallback while waiting for any async work that is downstream of the state change.

In Svelte, we don't do this. Instead, state changes that result in asynchronous work always have their effects deferred until the asynchronous work is complete. While that work is ongoing,$effect.pending() istrue. Anypending snippets are only shown when a boundary is first being created.

This does create the possibility that something distantly connected to a given piece of state has the power to delay (or prevent!) changes to that state from being reflected in the UI. We think this is preferable to the alternative (in which updates outside auseTransition or similar cause unwanted fallback UI to appear), though it may be necessary to develop techniques for identifying these chains.

Overlapping updates that touch the same state must be applied in linear order

In a case like this...

<p>{a} + {b} = {awaitfetch(`/add/${a}/${b}`).then((r)=>r.json())}</p>

...it's possible to imagine a scenario in which a change toa is followed by a change tob while the firstfetch is ongoing. If the secondfetch somehow finishes first, we don't want the firstfetch to be appliedafterwards, since the resulting UI would show stale values.

As such, a given async expression must only resolve after its previous versions have also resolved.

Async deriveds are eager

Normally in Svelte,$derived expressions use 'push-pull' reactivity — they are invalidated when their dependencies change (the 'push') but are not re-evaluated until something reads them (the 'pull'). This doesn't work for async deriveds, because if we waited until the value was read the resulting promise would never resolve in time.

Instead, an 'async derived' is really just an effect and a source signal in a trenchcoat. We evalute the expression in the effect, and when the promise resolves, set the source value (unless the effect fired again in the interim).

For the most part, you don't need to think about this. There is one important implication though — while it's possible to create an 'unowned derived' (in other words, a derived that is not part of the 'effect tree', such as one created in an event handler) it isnot possible to create an unowned async derived, because effects can only be created inside other effects. (Don't worry if you didn't follow this — it's inside baseball stuff, and describes an edge case you're unlikely to encounter. Svelte will tell you if you get this wrong.)

Context is preserved in expressions

When a reaction (i.e. an effect or derived) runs, we track its dependencies by seeing which values are read during its execution. In pseudo-code:

letdependencies=null;functionget(source){dependencies?.add(source);returnsource.value;}functionupdate_reaction(reaction){dependencies=newSet();reaction.fn();reaction.dependencies=dependencies;dependencies=null;}

(This is simplified and wrong, but you get the idea.)

For asynchronous functions, this presents a challenge. To understand why, consider the order in which things happen here:

functiona(){console.log('a 1');b();console.log('a 2');}asyncfunctionb(){console.log('b 1');await0;console.log('b 2');}a();

This will loga 1,b 1,a 2,b 2 — in other words despite the fact thatb isn't even awaiting an asynchronous value,b 2 isn't logged untilafter it has returned toa.

In Svelte terms, this would mean that$derived(await a + b) or an equivalent{await a + b} template expression would register a dependency ona butnot onb. But since we're a compiler we have a trick up our sleeves: we wrap theawait expression in a function that restores the effect context, so thatbis treated as a dependency.

On one level this is spooky compiler magic. But on another, it's just making the system work how a reasonable person would expect it to work. It does mean that if you extract the logic out into a function —{await a_plus_b()} — it will be treated differently, but during development Svelte will catch those cases and help you fix them.

No async$derived.by

While you can do this...

letx=$derived.by(async()=>awaity);

...x will then be aPromise, not the value ofawait y. There's no sensible place to put theawait that would result inx not being aPromise. (This is why it's pretty great that we're a compiler and can make the expression form the default, even though it makes other framework authors mad.)

If you have sufficiently complex logic that you need to use a function block, just declare the function and call it:

asyncfunctionadd(p1:Promise<number>,p2:Promise<number>){returnawaitp1+awaitp2;}letsum=$derived(awaitadd(p1,p2));

Note the aforementioned caveat around context preservation — make sure you pass state into the function, rather than having the function close over the state it references, so that dependencies are correctly attached.

Focused inputs are not overridden

Normally, state does not update in the UI until everything that depends on it has finished resolving. This doesnot apply to a focused<input> element, which in many cases will be the source of the state change in question — instead, the rest of the UI 'catches up' to the input.

Breaking changes

Because of how async reactivity works, there is one small and unavoidable breaking change:beforeUpdate and$effect.pre callbacks no longer run before control flow blocks are updated. If you're using those callbacks to set state that control flow logic depends on — which youabsolutely shouldn't be — then you may experience breakage. As a result, wemay have to wait until 6.0 for a non-experimental release of this stuff.

Ok so

That was a lot; congratulations to those of you still here. I am sure you have questions, and that's a good thing. This is the place to ask them, or to offer feedback on the design. Let's go!

You must be logged in to vote

Replies: 44 comments 166 replies

Comment options

so exciting!!

You must be logged in to vote
0 replies
Comment options

Love it's a discussion introduction for such an awaited feature!

You must be logged in to vote
0 replies
Comment options

This is really cool! I've been observing theasync branch for a while now, trying to figure out what the changes were going to be, how it would work, etc.

  1. How will pending state be handled? Currently,it seems like it just uses the last value, but I'm not entirely sure if that's the best choice.
  2. How do$effects not run until all async$deriveds are updated? According to Ryan Carniato in hisstream, this was an unsolvable issue without explicit dependencies.
  3. About when will this be merged? If this will be merged when Svelte 6 is released (which seems likely, since it's a breaking change), will this be the only major feature in Svelte 6, or are there more features planned?
  4. Why does async stuff dependent on sync stuff cause sync stuff to not update synchronously in the template? It seems unnecessary to delay synchronous updates.
  5. Why doesn'tdoubled ever update inthis code?
  6. Should there be arenderAsync function for SSRing async components?
  7. What other libraries/articles/frameworks inspired this?
You must be logged in to vote
4 replies
@SikandarJODD
Comment options

Doubled is updated..you can$inspect it :Preview

@Ocean-OS
Comment options

Doubled is updated..you can$inspect it :Preview

In that code, it is, but inmy code, it isn't.

@Azarattum
Comment options

  1. It seems convenient in some use cases (like the ones they've used in the examples). But I think we absolutely need a way to opt out of that behavior.
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

  1. How will pending state be handled?

The value is the value. The UI may display a previous value in order to maintain consistency, but it wouldn't make sense to have stale values elsewhere such as in event handlers

How do $effects not run until all async $deriveds are updated?

We just... don't run them? I haven't seen the stream so I'm not sure why it should be impossible.

  1. About when will this be merged?

No idea! Soon hopefully.

  1. Why does async stuff dependent on sync stuff cause sync stuff to not update synchronously in the template?

Because otherwise you'd see things like2 * 2 = 2 and that's insane

  1. Why doesn't doubled ever update in this code?

Because you're reading the state inside asetTimeout. There's no way for Svelte to associate the state read with the dependency in that case. Theremight be some way to catch those cases so we can warn on them, but it's probably just a matter of education

  1. Should there be arenderAsync function for SSRing async components?

There's an 'Async SSR' section above that addresses this

  1. What other libraries/articles/frameworks inspired this?

We researched prior art but didn't see anything we liked to be honest. We reached this design from first principles.

Comment options

When I read the document I was filled with excitement, fear and confusion
But after testing it a bit, only excitement remained
The only parts that don't sound so good are the behavior of states blocked by their asynchronous dependent reactions and derived states that 'catch up' to the input state, I can't think of a single occasion where these are desirable or expected behaviors
In this regard transitions seem infinitely superior, obsolete asynchronous derived states should simply be ignored without affecting the rest of the world
Otherwise, impressive work, congratulations to the whole team
I'm looking forward to the final result

You must be logged in to vote
15 replies
@Thiagolino8
Comment options

React — as soon as the delay exceeds the update frequency, the app breaks

Devbox not found 😢

Here's anexample of ignoring stale promises

Unfortunately, by manually orchestrating this state machine you lose the advantages of suspense
And even if you createa version that works with suspense, it doesn't work with $effect.pending

Another approach could be to use abort signals (#15845 (reply in thread))

I'm hopeful for the integration of abort signals, I believe it may be the right abstraction

I tried to makemy own integration, but it seems that the proposal is not yet prepared for rejected promises (the app simply crashes and the boundary does not capture any errors)

Edit: The issue was not the rejected promise, but an infinite loop for some reason
I fixed it, but $effect.pending is still broken (in a different way this time)

@Thiagolino8
Comment options

Here's anexample of ignoring stale promises

@Rich-Harris, It looks like you saved this example over the default example provided at the beginning of the discussion.

@Rich-Harris
Comment options

Rich-HarrisMay 4, 2025
Maintainer Author

Ah whoops! Fixed. Also made the devbox public.

I also added agetAbortSignal function that you can use inside effects and deriveds. It means you cando this sort of thing:

import{getAbortSignal}from'svelte';constresponse=$derived(awaitfetch(`/blah/${foo}`,{signal:getAbortSignal()}));constdata=$derived(awaitresponse.json());
@Thiagolino8
Comment options

Ah whoops! Fixed

Now it is a broken version of the getAbortSignal demo 😁
I loved the working version tho

@Rich-Harris
Comment options

Rich-HarrisMay 5, 2025
Maintainer Author

dammit! fixed again. not sure whybranch-async doesn't includegetAbortSignal

Comment options

Not sure if I missed something, but -- there is some error handling in this demo:https://svelte.dev/playground/24eec2a85770402eae633d06aec412a6?version=pr-15844

but, how do you do error handling generically for any await'd thing?

for example, in this parallel-promise template:

<li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li><li>canteloupes {awaitgetPrice('canteloupe')} each</li>

what do I do if I want to render errors ifgetPrice fails for apple and banana?

You must be logged in to vote
3 replies
@JReinhold
Comment options

I would assume that you should wrap apples and bananas in a<svelte:boundary> with afailed snippet.https://svelte.dev/docs/svelte/svelte-boundary#Properties-failed

<svelte:bondary><li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li>{#snippetfailed(error,reset)}whoops, apples or bananas failed.{/snippet}</svelte:boundary><li>canteloupes {awaitgetPrice('canteloupe')} each</li>
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Exactly — just the same as if there was noawait andgetPrice was a synchronous function that threw an error

@NullVoxPopuli
Comment options

thanks!

Comment options

Solid user here. Never usedcreateResource withstartTransition/useTransition.
I am using the ✨createAsync✨primitive which handles transitions under the hood automatically refetches when args passed to the async callback change, parallel fetching (no waterfalls) etc.
Async was never easier.

constdata=createAsync(()=>promiseFn(args));
You must be logged in to vote
5 replies
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Ok. ButcreateAsync isn't part of Solid, it's part of Solid Router; the Solid docs and tutorials steer people towardscreateResource so that's what we're talking about here, regardless of how things may look in 2.0.

The approach has its merits though I'm not personally sold on the programming model

@Malix-Labs
Comment options

I'm not personally sold on the programming model

What is "programming model" in that case?

@jer3m01
Comment options

Nothing in the currentcreateAsync is tied to the Router or 2.0.

It's not in core as we're focusing on the next major.
The import path/package really isn't relevant here.

More features will be included once 2.0 lands, but these aren't implemented nor restrict the currentcreateAsync.

@ryansolid
Comment options

@madaxen86 Currently Solid'screateAsync(current version)/createResource aren't noticeably different from each other.. Same non-blocking, parallel fetching, auto-serializing, auto-streaming, async SSR etc...createAsync was introduced to streamline the API to make it more composable (useful for interacting with Solid Router'squery andaction APIs), butcreateResource has had those capabilities for the past 6 years.

There are 2 shortcomings of the approach. Neither of them related to performance or architecture but to ergonomics.

First, our async isn't completely colorless in the sense that async values can be null, so people need to null check stuff is there until it is even with mechanisms like Suspense. So while you don't have to worry about passing promises around or the whole "where you fetch" dilemma client (non-RSC) uses of data-loading with Suspense have with React you introduce nullability into the tree.

The second is Suspense being too eager to bail out. It is really easy to trigger Suspense on some small async update on the page causing return to fallback. Using Transitions is one way to avoid this, but most of the time people would probably rather just tear. This has lead to stuff likeuseDeferredValue in React and.latest on our resources. The truth is 99% of people will never knowingly use Transitions. They are mostly there for things like Routing. The cases that Rich refers to in the forking section. So they aren't generally part of the experience of developing. However aggressive Suspense bailout can get people there much earlier than they intend.

Of course, sitting with these issues over the years these are things we are already working on remedying in the next major version. But it is worth noting the proposal above for Svelte doesn't have these issues. The async holding along the graph +$effect.pending() removes the need for aggressive Suspense(boundary) bailout, and the compiled use ofawait plus the same holding removes the non-nullability. With this foundation the other async adjacent features should layer on quite nicely. This is very exciting progress in this area.

@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

@ryansolid happy to see you here! Thanks for reading the proposal.

What is "programming model" in that case?

Just the fact that I'm not dealing with promises in a way that feels JavaScript-native, but rather via a framework's abstraction. I totally understand why it is the way it is, and it's very much a matter of taste, but I don't think it would be the right design for Svelte. Ido like how aggressivelycreateAsync/createResource discourage waterfalls; in the worst case our design trades off a little performance for ergonomics here (though on the flip side it means that people are encouraged to learn patterns and techniques for avoiding waterfalls that apply toall their code, not just their components).

The 'JavaScript-native' thing is obviously a minefield. Svelte is transforming your async code and doing all sorts of behind-the-scenes scheduling, but React and (IIUC) Solid are throwing to trigger Suspense; to me these feel equivalently magical. YMMV!

Comment options

Unless we want to createserver endpoints for everything we want tofetch inside a component, we'll need tools for interacting with the server. Those tools will need to consider security, HTTP caching, mutations and invalidation, optimistic UI, batching, streaming, custom serialization, type safety and lots of other things.

We have a neat little super-lightweight RPC (lighter than tRPC) setup that

  • takes an "API object" consisting of functions to call (only requirement is that the functions have a single object argument)
  • wraps this object in a server-side API endpoint that translates URL paths into a path into this object, calls the function with the given query parameters, and returns its serialized response
  • and, for the client, provides a nested proxy object thathas the same type as the original API object. No code generation/compilation necessary!

This basically turns anything that we put into the API object into an async function callable from the client, with the same signature as the original server-side function. Also, since we're working with plain functions, things can be trivially wrapped with HOF et al both on the server and the client to implement concerns like authentication, validation, caching, etc.

This has been really fun to use, and I'm happy to share more if there's interest in this.

You must be logged in to vote
13 replies
@gterras
Comment options

return await db.user.create(user);

Is theawait ideal here?

@Rich-Harris
Comment options

Rich-HarrisMay 4, 2025
Maintainer Author

It's an unnecessary extra microtask but I find it conceptually clearer. YMMV

@t1u1
Comment options

@hmans we're exploring the RPC space (@dummdidumm in particular is deep in this rabbit hole at present)

Anywhere we could follow along? Would be an immense timesaver to have an integrated RPC in sveltekit.

@weepy
Comment options

I LOVE THIS - is there a branch or place for discussion ?

@chanmathew
Comment options

THIS IS SO CLEAN! Taking it one step further to have Tanstack query-like destructuring of the data, loading, error, would be chef's kiss.

Comment options

If unrelated state changes while an update is pending, it will be visible immediately (assuming it doesn't separately cause asynchronous updates).

Ah, so no freezing states in child components too, I suppose? I was hoping this was the case, it would certainly help with something like mobile stack navigations, carousels, accordions or drawers where youdo want a portion of your component tree to be frozen (seesvelte-freeze for the general idea, andsvelte-stakkr for a router building on that idea)

The entirety of svelte-freeze could be simplified into this single component, and most importantly removes the need for willing packages to opt-in to the freezing functionality.

<scriptlang="ts">import {untrack,typeSnippet }from'svelte';interfaceProps {frozen:boolean;children:Snippet;}const { frozen, children }:Props=$props();const PROMISE=newPromise(()=> {});</script><svelte:boundary>{#iffrozen}{awaitPROMISE}{/if}{@renderchildren()}{#snippetpending()}<!-- empty -->{/snippet}</svelte:boundary>

I would admit that it's going to be a lot more complicated behind the scenes though, since now you need to have a way to have a derivation that runs outside of that suspension, so that you can check for$effect.pending() (I personally need this to ignore events from mutation/resize observers as elements are being frozen/unfrozen, maybe it can be an$effect.pre thing)

It's certainly something that can be better handled by a different mechanism for sure, just like how React's<Activity>/<Offscreen> is separate from<Suspense>, but that certainly hasn't stopped React (Native) apps from toying with<Suspense> to get this exact functionality.

You must be logged in to vote
3 replies
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Right, so if e.g.page.url andpage.params etc change, then everything derived from them (await loadStuff(page.params.stuff)) will update at the same time, wherever they appear in the app. But if you have something that doesn't depend on those things (like{time.now} or{mouse.x}x{mouse.y}) then it will update immediately. I assume that's the desired behaviour?

@mary-ext
Comment options

Yeah, I had hoped thattime.now wouldn't change so long asawait loadStuff() is still pending

@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Why?

Comment options

There's no sensible place to put the await that would result in x not being a Promise.

I don't understand this, I personally dislike $derived and $derived.by not working identically. Maybe someone could explain to me like I'm a 5 year old?

You must be logged in to vote
12 replies
@jjones315
Comment options

100% agree, i think the fact that$derived() accepts an expression should be leveraged. I was just giving concrete examples of some alternatives since that tends to help me when looking at decisions like this. i hadn't actually though through the pitfalls of$derived.async(...);. Then having to statically analyzeconst output = await $derived.by(…) has some very clear pitfalls. like what does

constfooPromise=$derived.by()//.. several lines of codeconstfoo=awaitfooPromise;

do, this would be very easy for someone to do as a refracting and completely break how something works without being clear why it broke.

Should of included the pitfalls directly in the initial message i was pre-coffee :)

Looking forward to this shipping, if this works as promised its going to be amazing.

@GauBen
Comment options

wait, am I supposed to dolet x = await $derived(...) orlet x = $derived(await ...)?

Could the compiler allow both? Evenawait $derived(await ...), while useless, could be valid async svelte code

@gterras
Comment options

Evenawait $derived(await ...), while useless

useless AND nightmarish

@rChaoz
Comment options

Exactly this. You can't use await outside an async function, but if you pass an async function to $derived.by then the value will be a promise

@Rich-Harris I still don't understand this. Why wouldn't something likethis work:

declarefunction$derivedBy<T>(func:()=>T):Awaited<T>// the type of this is number, not Promise<number>letnum=$derivedBy(async()=>await5)

...and the compiler can just treat it as if it were written like this instead:

asyncfunctionderivedTemp(){returnawait5}letnum=$derived(awaitderivedTemp())

And, to avoid a breaking change, a new name (e.g.$derived.byAsync or$derived.byAwait) can be used.

Update: I just realised this can also be implemented in user-land, using an IIFE:

letnum=$derived(await(async()=>{await5})())

But, IMO this is not ideal. And, if it, or the workaround using regular functions, defeat the purpose of$derived.byAsync, then the purpose of$derived.by is also defeated by the same concepts (without async), yet it exists.

@Rich-Harris
Comment options

Rich-HarrisMay 15, 2025
Maintainer Author

I explained it above#15845 (reply in thread)

Comment options

I wonder if it could be possible to somehow abort promises that are no longer needed, so that there aren't unneeded in-flight requests due to network lag

As I understand, once "Overlapping updates that touch the same state must be applied in linear order" is implemented the following would happen:

  • There is an app with a drpdown to check produce price, user quickly clicks on bananas, apples, mangos. There are now 3getPrice() requests in the air.
  • The apple request hangs, maybe not cached.
  • In the background the mango price resolves, but the user needs to wait until apples resolves before being able to see the mango price.

So instead by aborting the older fetches the developer explicitly says "I don't care about this anymore, just give the user the latest value"

Something like this maybe?

exportfunctiongetPrice(produce){returnawaitfetch("/api/price/"+produce,{signal:$effect.abortSignal()})}
You must be logged in to vote
2 replies
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

We actually implemented this exact thing a while back (as an import rather than a rune, but same semantics) but decided not to land it because your console quickly fills up with DOMExceptions that you can't really get rid of (unless you store a reference to the promise returned fromfetch and attach a floating noopcatch handler).

But with async stuff it does potentially become more valuable, so it might be worth revisiting

@JonathonRP
Comment options

I wanted to up vote revisit the abort signal, I watched that PR and was really looking forward to it.

Comment options

Regarding async derived dependencies effects to be blocked until async derived resolves - you mention inputs being the exception. What about cases like a custom inputs or search bar with a clear button - pressing clear should clear that input and initiate an async search with empty value(it returns unfiltered entries then). There would be no focused input here so input will be cleared only after search resolves?

You must be logged in to vote
4 replies
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Great question. The short answer is yes, if you press 'clear' then theinput won't clear until the results have come in. In that case you would need to express that intent ('clear the input as well as resetting the value')programmatically:

<buttononclick={()=>name=input.value=''}>clear</button>

As for custom inputs, it works by checking if the current element isdocument.activeElement. It's entirely possible that this will break for web components, because there is no limit to how much sadness they can cause.

@Azarattum
Comment options

There are many use cases where we want to respond instantly to user input and fetch something in background. So, we definitely need a way to control that since both behaviors are useful.

Maybe for opt in:

lettext=$state.deferred("");letresults=$derived(awaitsearch(text));

Other options.lazy.

Or for opt out:

lettext=$state.eager("");letresults=$derived(awaitsearch(text));

Other options.immediate,.instant.

@santiagocezar
Comment options

Another idea, syncing only between the parts of the UI that have the same closest parent boundary (or possibly another special element), for example:

<script>import {delayed }from'./utils.js';let x=$state(0);</script><svelte:boundary><inputtype="range"bind:value={x} /> <span>{x}</span><svelte:boundary><inputtype="range"value={awaitdelayed(x)}disabled />        <span>{x}</span>{#snippetpending()}<p>loading...</p>{/snippet}</svelte:boundary></svelte:boundary>

The outsideinput andspan would get updated immediately after the user interacts, while the inner ones update only afterdelayed resolves. On the surface, the way it works feels kinda intuitive, but I'm not sure if it's the best solution.

@Rich-Harris
Comment options

Rich-HarrisMay 1, 2025
Maintainer Author

That was one of our first designs. Long story short it leads you into impossible-to-resolve situations

Comment options

https://svelte.dev/playground/767e0bfd75614664a41ba73f28cc424c?version=pr-15844

Is this a case of 'Overlapping updates' stuff that is yet to be resolved? Or is this a different bug? I'm confused whydoubled can de-sync, but thecount state variable updates correctly. In my understanding,count,doubled, anddoubledAsync are all part of the same "batch" and should never de-sync from each other?

You must be logged in to vote
5 replies
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

Looks like a new bug, will investigate

@bennymi
Comment options

Is this another bug? Seems like$effect.pending() isn't changing to false:https://svelte.dev/playground/5c76337c47a1413f8b86f148bb97a553?version=pr-15844

@Rich-Harris
Comment options

Rich-HarrisMay 1, 2025
Maintainer Author

Yeah there are bugs around$effect.pending()

@rChaoz
Comment options

https://svelte.dev/playground/767e0bfd75614664a41ba73f28cc424c?version=pr-15844

For me, simply double-clicking oncount desyncs it.

@Rich-Harris
Comment options

Rich-HarrisJun 2, 2025
Maintainer Author

Thanks for the test cases — these are all now fixed

Comment options

I know async SSR was mentions as a possible future development. In its current state are the component level await started on the server? or do they begin after hydration on the client? i suppose hydration will likely be much faster if it hits a pending early enough, but it still seems like a pretty big gotcha if request don't begin until after hydration.

You must be logged in to vote
1 reply
@Rich-Harris
Comment options

Rich-HarrisApr 29, 2025
Maintainer Author

If you look at the JS Output tab of theplayground and switch toserver mode you'll see what happens — we literally ignore everything except thepending snippet:

image

In other words for now everything starts in the browser. Obviously that's not tenable in the long term; we want to be able to pass promises from the server to the client.

It's not straightforward though. Consider a case like this:

<script>if (browser) {constx=$derived(awaitfoo());consty=$derived(awaitfoo());// ...  }else {constz=$derived(awaitbaz());  }</script>

Where does the serialized data 'go'? If we somehow bake the values into a comment that the component reads as it hydrates, then it will expect two payloads but we've only baked in one. And it's not even one that we want to use!

Or this:

<script>import {blah }from'./stuff';importChildfrom'./Child.svelte';</script><Childblah={awaitblah} />
<script>import {blah }from'./stuff';let props=$props();</script><p>{props.blah===awaitblah}</p>

This needs to render<p>true</p> regardless of what type of valueblah resolves to, so we can't just serialize the data in isolation for each component; we would need to have some central registry that every component can refer to. Something like this, perhaps:

const{ head, body, data}=awaitrenderAsync(App,{...});return`<!doctype html><html>  <head>    <meta charset="utf-8">    {head}  </head>  <body>    <div>${body}</div>    <script type="module">      import { hydrate } from 'svelte';      import App from './App.svelte';      hydrate(App, {        target: document.querySelector('#target'),        data:${serialize(data)}      });    </script>  </body></html>`;

(I'm glossing over a lot of stuff but you get the idea.)

Alternatively, Svelte could delegate it to frameworks like SvelteKit which could provide their own abstractions (fetch caching, RPC utilities etc) and if a given expression doesn't have pre-rendered data ready to hydrate,hydrate could simply wait until the client can fix the gaps before returning.

Shorter version: there's a lot of stuff to figure out here and we don't yet know what it'll look like, but it's very much on the radar.

Comment options

This is great 💪

You must be logged in to vote
0 replies
Comment options

More of an SSR question: has there been any more research or thought into how streamed components with errors will be handled?

I remember reading another thread that was talking about including a meta tag if a component had an error so the page wouldn't get indexed. Interested to see where Svelte ends up.

You must be logged in to vote
4 replies
@Rich-Harris
Comment options

Rich-HarrisApr 30, 2025
Maintainer Author

I'm enough of a purist that I struggle a bit with the idea of handling errors by shoving a<meta> tag that indicates an error inside a 200 response. It'sprobably fine, but I don't feel confident that it will work reliably everywhere (like, what if the page has a cache header likes-maxage — can you stop your CDN from caching it?)

Instead, I quite like the idea of separating critical stuff (status code,<head>, some of the<body>) from non-critical stuff — perhaps something like this:

response.write(`<!doctype html><html><head>`);try{// `stream` returns `Promise<{ head: string, body: AsyncIterator<string> }>`const{ head, body}=awaitstream(App,{...});constresponse=newStreamedResponse(200);response.write(head);response.write(`</head><body><div>`);asyncfunctionnext(){const{ value, done}=awaitbody.next();if(done){response.write(`</div><script>${HYDRATE}</script></body></html`);}else{response.write(value);next();}}next();returnresponse;}catch(error){returnnewResponse(getStatusCode(error),renderErrorPage(error));}

We could demarcate non-critical content with an attribute on<svelte:boundary>:

<script>import {page }from'$app/state';import {getPost }from'$lib/api';constpost=$derived(awaitgetPost(page.params.slug));</script><!-- critical --><svelte:head>  <title>{post.title}</title></svelte:head><h1>{post.title}</h1><divclass="post">{@htmlpost.content}</div><!-- non-critical --><svelte:boundarystreamable>  <Comments />  {#snippetfailed())<!--ifanerroroccurswhilerenderingcomments,thissnippetgetsincludedintheserver-renderedHTML-->  {/snippet}</svelte:boundary>

Inside a streamable boundary, certain restrictions could apply, like no<svelte:head>. Anyway, just spitballing at this stage. (Not pictured: a way of capturing the error during SSR so that you can log it, or fail if prerendering.)

@rossrobino
Comment options

Yeah I like it! I can't think of a better way. If you want to stream something critical it just comes with the caveat that it might error and still send a 200. So best practice remains to only stream non-critical content.

For a client side navigation this wouldn't matter as much right? Everything could just be streamed as it resolves?

@Rich-Harris
Comment options

Rich-HarrisApr 30, 2025
Maintainer Author

Ah yep, the example wasmeant to show immediate writing of critical content but I wrote it wrong 😆

For client-side nav yeah, I think you could stream everything

@rossrobino
Comment options

Awesome! This is going to be great

Comment options

I'm the author ofTelefunc whichwas mentioned by Svelte Summit.

I'm glad to see Telefunc inspired SvelteKit to re-create Telefunc's design!

Currently, Telefunc doesn't have that many features and re-creating Telefunc is relatively easy.

That said, Telefunc's goal is to support alot more features (including some features mentioned in the conference) while enabling frameworks such as SvelteKit to deeply integrate Telefunc.

For example, real-time (two way communication) is very tricky to get right. I've some ideas and it would be great to design it together with the SvelteKit team — in case there is interest.

Another example is error handling, which is an interesting topic as well. (The combination tRPC + TanStack Query is one example, but I believe there are much better ways to do it.)

RPC's renaissance (it's actually anold technology — older than REST!) is just at its beginnings and I see an opportunity to create a common RPC infrastructure shared between frameworks.

RPC has a bright future (full of promises). The door is open on my side to collaborate.

You must be logged in to vote
2 replies
@Rich-Harris
Comment options

Rich-HarrisMay 28, 2025
Maintainer Author

Hey! In principle the door is open on our side too. In practice it may prove tricky, because the proposal we're about to share (this week or next) integrates with the rest of SvelteKit in a way that might be difficult to do in a less opinionated library. For example aquery in our design isn't just a wrapper around an HTTP transport mechanism, it also works with our reactivity system to manage a local cache, and has a mechanism for optimistic updates. (Meanwhile acommand causes currently active queries to clear their cache and re-run, unless you explicitly refresh queries in a more granular fashion.)

We also have form functions that are very specific to Svelte, and prerender functions that are very specific to SvelteKit. All of this works with SvelteKit's (de)serialization mechanism which allows everythingdevalue allows, plus anything you've defined in your owntransport hooks, plus nested Promises, plus (soon, hopefully) streams and async iterables. And we'll likely have some opinionated handling of version skew.

So there are likely too many implementation details that can't really be outsourced — the coupling of the different pieces within the frameworkis the real value. What's left is the transport mechanism, which as you say is relatively straightforward (though it admittedly becomes slightly less so when you factor in batching and real-time).

I think what probably makes sense is for us to build this within SvelteKit to begin with, and then once we ship something we can start to get a sense of which pieces could become part of a common base.

@brillout
Comment options

Seems like a good plan! And I agree: I also ain't sure whether/how a full-fledged RFC infrastructure can be made agnostic. Looking forward to your RFC!

Comment options

I'd like to bring up the behaviour of delayed synchronous results and what I found to be surprising behaviour.

Experimenting with the PR, I extended the simple example so that there are two variablesa andb, keeping the existing delay ona inside the boundary but makingb plain. Then I set up buttons to increment eithera,b, or botha andb at the same time.

<script>import {delayed }from'./utils.js';let a=$state(0);let b=$state(0);</script>increment:<buttononclick={()=>a+=1}>a</button><buttononclick={()=>b+=1}>b</button><buttononclick={()=> {a+=1;b+=1}}>both</button><p>a = {a}</p><p>b = {b}</p><h2>Boundary</h2><svelte:boundary><p>a * 2 = {a} * 2 = {awaitdelayed(a*2,1000)} (delayed)</p><p>b * 2 = {b} * 2 = {b*2}</p>{#snippetpending()}<p>...loading...</p>{/snippet}</svelte:boundary>

(https://svelte.dev/playground/7173ec0d84ed42bc85d6c8dc8c926fe2?version=pr-15844)

Behaviour:

  • "a" button causes a delayed async update toa as expected
  • "b" button causes an instant sync update tob as expected
  • "both" button updates both, resulting in a delay updatingb untila is complete
  • clicking "a" then "b" allowsb to complete immediately whilea is still running
  • clicking "both" then "b" causes a mixture of delayed and instant updates tob overlapped

So the link that causes sync updates to be delayed appears to be if they are altered in the same tick as an async one?

I don't know if this behaviour is technically considered right or wrong, but it sure is surprising, and surprising behaviour is always a worry. In particular the mixuture of delayed and instant updates tob overlapping is bound to be a very unhappy surprise.

That said, I don't currently have any constructive suggestions to improve the situation :(

You must be logged in to vote
4 replies
@Rich-Harris
Comment options

Rich-HarrisJun 1, 2025
Maintainer Author

You found a bug, which is now fixed on the branch. You might still find the behaviour slightly unintuitive at first though — if you click 'both' then 'b' in quick succession, there'll be a single visible update in whicha increments by 1 andb increments by 2 (previously, the second update tob would fall between the cracks).

This is necessary to avoid tearing — when you updatea andb in the same moment, they form a group of updates, and everything that updates asynchronously as a result of that state change is similarly grouped. (If you want them to be treated as separate updates, insert anawait tick() betweena += 1 andb += 1).

If you updateb while that group of updates is pending, the update has to be deferred because otherwise we would reintroduce tearing (since the first update tob would be visible before the update toa).

@rmunn
Comment options

(If you want them to be treated as separate updates, insert anawait tick() betweena += 1 andb += 1).

This will make a good example for the documentation once the branch is settled enough that the docs start being written.

@rmunn
Comment options

What ifboth had been written asb += 1; a += 1? Would anawait tick() still be necessary to separate the two updates if desired? Or would b updating first, when no delayed update had happened yet, have caused an immediate b update then followed by a delayed a update?

@Rich-Harris
Comment options

Rich-HarrisJun 1, 2025
Maintainer Author

They're equivalent - updates are grouped if they happen in the same microtask

Comment options

Are there any plans for an equivalent of<SuspenseList>? My own experience is that it is a huge boost for creating smoother interfaces.
There are currently hooks in place that allow this to be implemented in userland (REPL) but the problems it solves are so common that it feels like it might be better off as part of the core.

Displaying a list of comments and you need to fetch each user's avatar? You don't want to delay displaying any comments until all the avatars are done loading, but you also don't want the avatars popping in a random order either.

Have three sequential blocks that depend on different data? You really don't want the user to see

Loading...ContentLoading...

If the user tries to interact with that second block, it will lead to frustration since a page layout shift will occur as soon as the first block loads.

You must be logged in to vote
0 replies
Comment options

Is there any way to opt out of anti-tearing?

In my opinion, changes that should be synchronous behaving as asynchronous makes the entire UI feel buggy and slow.

I feel that the result is better when the developer makes it clear which part of the UI is out of date using some pending state (like $effect.pending if it were local to the boundary)

The desired behavior
Gravação de tela de 05-06-2025 10:46:44
Current behavior
Gravação de tela de 05-06-2025 10:46:03

You must be logged in to vote
3 replies
@rmunn
Comment options

You can get the desired behaviorwith{#await} blocks. Note that my example doesn't preserve the old value, because I was trying to keep it simple, but you could keep the old value around for displaying until the new one shows up using something likehttps://runed.dev/docs/utilities/previous.

@WaltzingPenguin
Comment options

It would be irritating to do for every value but, if you need to just opt out for one or two things,setTimeout breaks out of Svelte's dependency graph.REPL

@dummdidumm
Comment options

I think a case like this is probably better served with using a resource-like API, where you access the result via a property that updates whenever a new value comes in - basically we need (and will have) something similar to for example Solid's resource API that you linked to.

Comment options

You must be logged in to vote
2 replies
@ollema
Comment options

hello mr code god, did you read through the original post before posting this question?

@codegod100
Comment options

obviously not lol comment deleted

Comment options

Willawait support async iterables?

You must be logged in to vote
1 reply
@Rich-Harris
Comment options

Rich-HarrisJun 18, 2025
Maintainer Author

No, that would be surprising behaviour. But you could certainly convert an async iterable into a thenable

Comment options

Finally I took the time to play more with this branch, and I already love it.

Few feedback in random order(hope it's not to late to give a feedback):
a/ I find the messageawait_outside_boundary confusing.Maybe it's my english ^^. Today:

Cannot await outside a<svelte:boundary> with apending snippet

It makes me think that we should NOT have a pending snippet, but in reallity, we must have one. It's probably for good practice to enforce pending, ok. Would be great to have this info in the doc. (once done)

b/ $effect.pending() globality

I started to do:

<svelte:boundary>  {awaitlist(limit)}  {#snippetfailed(error)}    <p>oops: {error.message}</p>  {/snippet}  {#snippetpending()}    <p>First pending...</p>  {/snippet}  {#if$effect.pending()}    <p>subsequentpending</p>  {/if}</svelte:boundary>

And its working well when I have one async story. As soon as I add more, I see a lot ofNext pending.

Maybe having something like<svelte:boundary subsequentPending> could help here to express the locality ?

Here is myplayground.

You must be logged in to vote
1 reply
@elliott-with-the-longest-name-on-github
Comment options

Rich is working on making$effect.pending local to the nearest boundary right now :)

Comment options

Quick question: wouldn't thesvelte:boundary limitation not allow await statements in top-level component (e.g.+layout.svelte) script blocks, as they cannot be encased in a<svelte:boundary> tag?

You must be logged in to vote
7 replies
@geodic
Comment options

Ah, that makes sense...

@realfakenerd
Comment options

The main reason for this limitation is because SSR isn't yet supported...

@elliott-with-the-longest-name-on-github why it isn't supported? I thought it was supported because of theexport const csr = false inside+page.ts

@elliott-with-the-longest-name-on-github
Comment options

@realfakenerd SSR isn't supported yet because we haven't implemented support for it yet 😉 (I'm being a little snarky but that is the truth!)

SSR is still a synchronous process, which means we can't supportawait in components during SSR. We get around this by saying "any components usingawait must be in a boundary with apending snippet", because that means as soon as we encounter a boundary with apending snippet during SSR, we can render the pending snippet and avoid trying to render anything asynchronous.

After this is merged as an experimental feature, we'll start work on asynchronous SSR, which will mean SSR can wait on your promises to resolve and render your components. This is kind of a huge body of work, though, as it involves figuring out when async components should be blocking/nonblocking (streaming), how to hydrate asynchronous stuff on the client, and lots of other internal bits and bobs. To avoid literally never shipping anything due to massive scope, we've opted for the two-step, CSR-then-SSR, release-as-experimental approach.

@realfakenerd
Comment options

@elliott-with-the-longest-name-on-github i think i get it, it kind of works but in a synchronous way, what we don't have now is the async SSR, right? 🤔

But when we get that, top level await will be possible? Maybe without needing any hint or if hint needed the way i suggested with a<script async>...</script>?

@elliott-with-the-longest-name-on-github
Comment options

Yes exactly!

Comment options

Is SSR support a long way away ?
On Thu, 10 Jul 2025 at 19:08, Elliott Johnson ***@***.***> wrote: The main reason for this limitation is because SSR isn't yet supported -- i.e. we *have* to have a pending snippet to fall back to during SSR. Once SSR is supported, we can make boundaries optional, and frameworks like SvelteKit can wrap your layout in a boundary for you so that they can render your +error.svelte or (maybe, doesn't exist yet) your +loading.svelte. — Reply to this email directly, view it on GitHub <#15845 (reply in thread)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAAGNFPGWLD7P47I42VFRD3H2MYZAVCNFSM6AAAAAB4BQKD3CVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTGNZSGMZDIMQ> . You are receiving this because you commented.Message ID: ***@***.***>
You must be logged in to vote
0 replies
Comment options

https://pkg.pr.new/svelte@async currently points to svelte 5.28. Can any of the maintainers update it?

You must be logged in to vote
1 reply
@Rich-Harris
Comment options

Rich-HarrisJul 10, 2025
Maintainer Author

No, we don't control pkg.pr.new (that would be@Aslemammad). At present, links with branch names stop being updated once there's a PR associated with the branch, I don't believe it's possible to update it on our end.

Comment options

... And it's released! You can now use this in Svelte 5.36.0 rather than running off thesvelte@async branch.experimental.async compiler option is still required.

You must be logged in to vote
0 replies
Comment options

i get error running something like so:

<script>    function fn(x) {        return new Promise((f) => {        setTimeout(() => f(x), 200)         });    }    let a = $state(1)    let b = $derived(await fn(a))</script><svelte:boundary>    {b}{#snippet pending()}<p>loading...</p>{/snippet}{#snippet failed()}<p>failed</p>{/snippet}</svelte:boundary>
Svelte error: await_outside_boundaryCannot await outside a `<svelte:boundary>` with a `pending` snippethttps://svelte.dev/e/await_outside_boundary    at await_outside_boundary (playground:output:143:18)    at get_pending_boundary (playground:output:1255:4)    at suspend (playground:output:2152:18)    at $$body (playground:output:4790:21)    at App (playground:output:4887:3)    at eval (playground:output:4439:17)    at update_reaction (playground:output:3632:57)    at update_effect (playground:output:3812:19)    at create_effect (playground:output:3003:5)    at branch (playground:output:3121:10)

am i missing something? i thought we could await directly within the $derived rune

You must be logged in to vote
12 replies
@MPizzotti
Comment options

You can.Inside a boundary

but there isn't a way to use the svelte:boundary within the <script> tags, or have i missed something ?

@Rich-Harris
Comment options

Rich-HarrisJul 15, 2025
Maintainer Author

<svelte:boundary>  <TheComponentContainingTheDerivedWithTheAwait />  {#snippetpending()}    <p>loading...</p>  {/snippet}</svelte:boundary>
@7nik
Comment options

7nikJul 15, 2025
Collaborator

<svelte:boundary>  <MyComponent /><!-- this component can use await in the script -->  {#snippetpending()}    <p>loading...</p>  {/snippet}</svelte:boundary>

Also, REPL site was updated to implicitly wrap the entire App in a boundary.

@stefa168
Comment options

Gotcha@Rich-Harris, that's what I was asking about regarding an error more specific for this issue

REPL site was updated to implicitly wrap the entire App in a boundary

And instead in our case when developing an application the boundary won't be present by default, so we'll have to add one at the root level, correct?

@7nik
Comment options

7nikJul 15, 2025
Collaborator

Currently - yes

Comment options

Hello guys!

would this be valid async svelte?

letdetails=$state(awaitgetPokemonDetails())
You must be logged in to vote
3 replies
@Rich-Harris
Comment options

Rich-HarrisJul 16, 2025
Maintainer Author

sure is!

@saent-x
Comment options

Oh nice! I guess the linting isn't updated yet i still get errors.

Although I encountered an error where the UI wasn't loading some css/js and made some part of the page non-reactive to the point of freezing.
I documented the issues here16383

@baseballyama
Comment options

eslint-plugin-svelte@3.11.0 is supported async svelte.
https://github.com/sveltejs/eslint-plugin-svelte/releases/tag/eslint-plugin-svelte%403.11.0

Comment options

I'm sorry if this has been asked before, but is it possible to use this feature withStreaming with promises?

You must be logged in to vote
1 reply
@fmorency
Comment options

I tried playing with it and logged#16403.

Comment options

I still get

'await' expressions are only allowed within async functions and at the top levels of modules.

How to fix that warning? Cuse the code is working fine.

You must be logged in to vote
9 replies
@dummdidumm
Comment options

This is a language tools issue, supportawait hasn't landed in the VS Code extension and svelte-check yet (but working on it as we speak)

@codeit-ninja
Comment options

Ah, that makes sense. Do you have a ETA? This async is such good addition to svelte, want to use it without@ts-expect-error ^^

@elliott-with-the-longest-name-on-github
Comment options

ETA is as soon as he can get it done 😆 which, knowing Simon, is very fast!

@dummdidumm
Comment options

Released, make sure to update to the latest version of the VS Code extension / svelte-check

@codeit-ninja
Comment options

Thats amazingly fast ^^, thanks 🚀🚀

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Labels
None yet
62 participants
@Rich-Harris@weepy@hmans@rmunn@arxpoetica@brenelz@NullVoxPopuli@stefa168@AlecAivazis@brillout@fmorency@samal-rasmussen@ryansolid@chanmathew@jycouet@JReinhold@WaltzingPenguin@lukeed@dummdidumm@Stadly@Gin-Quinand others

[8]ページ先頭

©2009-2025 Movatter.jp