Invalidate fetched URLs
See original GitHub issueIs your feature request related to a problem? Please describe.
Suppose you were building an e-commerce site. You might have a shopping cart icon in your root src/routes/$layout.svelte component. Inside src/routes/products/[category]/[id].svelte you might have an ‘add to cart’ button. When the user clicks the button, the cart icon should update.
One perfectly valid way to model this would be to put the user’s cart on the session store, and then update the store after the POST triggered by ‘add to cart’ succeeds:
async function submit(e) {
e.preventDefault(); // because we're progressively enhancing the 'add to cart' <form>
const product = await fetch(this.action, {
method: this.method,
body: new FormData(this)
});
$session.cart.products = [...$session.cart.products, product];
}
But you might have valid reasons for not wanting to put that data in session — perhaps the cart is only visible on some parts of the app and you don’t want to always pay the cost of serializing the data. Instead, you might do something like this:
<!-- src/routes/$layout.svelte -->
<script context="module">
export async function load({ fetch }) {
const cart = await fetch('/cart.json').then(r => r.json());
return {
props: { cart }
};
}
</script>
This creates a problem. POSTing to /cart.json will add the product(s) to the cart, but will no longer cause the cart icon to update, because the layout component has no way of knowing that the result of fetching /cart.json has changed.
Describe the solution you’d like
Since we’re using the passed-in fetch, we know which URLs the layout component depends on. We could therefore expose an API like this:
+// may not be the best place for this functionality, but we can bikeshed that
+import { invalidate } from '$app/navigation';
+
async function submit(e) {
e.preventDefault(); // because we're progressively enhancing the 'add to cart' <form>
const product = await fetch(this.action, {
method: this.method,
body: new FormData(this)
});
- $session.cart.products = [...$session.cart.products, product];
+ invalidate('/cart.json');
}
SvelteKit could straightforwardly keep track of which load functions fetched the invalidated URL, and rerun them (assuming the components they belong to are still mounted), much as we already do for load functions that use session when that store changes value.
Describe alternatives you’ve considered This is a somewhat low-tech solution. A more common approach might be to use a full-blown fat-client state management system that has a copy of the model in memory (see e.g. Firebase). One possibility would be to integrate more closely with such systems or even build one ourselves.
Personally I’m more inclined towards simple, explicit mechanisms that are easy to implement and understand; in any case this would be complementary towards the more full-blown solutions (or at the very least, not in conflict).
Other possibilities that I’m not keen on:
- Intercepting all non-GET fetches and invalidating all
loadfunctions automatically - Offering a way to invalidate everything in one go, rather than invalidating specific URLs
How important is this feature to you? It’s a nice-to-have — it solves a problem that can already be solved in various ways, but arguably in a more elegant way. And it’s the one feature I’ve seen in Remix that we don’t already have a (more elegant, IMHO 💅 ) equivalent of that I’m aware of 😃
(Their version re-runs all loaders indiscriminately whenever an ‘action’ — their word for POST/PUT/PATCH/DELETE etc requests — takes place. AFAICT it wouldn’t work with external APIs, just the app’s own endpoint. But it does have the nice characteristic that it runs automatically.)
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:10 (6 by maintainers)

Top Related StackOverflow Question
I have a similar use case, we have some pretty complex
fetchstatements we’re making base on the query params on the page, and it’s a pain to have reconstruct the entire query string for eachinvalidate.Does
invalidatealso updates the URL of the current page? It appears it doesn’t. I have a use case where I would like to share the URL of the page after invalidation. @Rich-Harris @Conduitry