Skip to content

noSvelteAsyncStore (JavaScript)

Language JavaScript (and super languages)
biome.json
{
"linter": {
"rules": {
"nursery": {
"noSvelteAsyncStore": "error"
}
}
}
}

Disallow passing async functions to Svelte stores.

The writable(), readable(), and derived() functions from svelte/store accept a function as their second argument, and Svelte uses the value that this function returns. An async function always returns a promise instead:

  • For writable() and readable(), Svelte calls the returned value when the store is no longer used, for example when a component that reads the store is removed from the page. Calling a promise throws an error.
  • For derived(), Svelte ignores the promise, so the cleanup never runs. If the function takes a single parameter, the store holds the promise instead of the result.

To do async work, keep the function synchronous and start the work inside it, then call set() once the result is ready.

import { writable } from "svelte/store";
const user = writable(null, async (set) => {
set(await fetchUser());
});
code-block.js:2:29 lint/nursery/noSvelteAsyncStore ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ This async function is passed to writable().

1 │ import { writable } from "svelte/store";
> 2 │ const user = writable(null, async (set) => {
│ ^^^^^
3 │ set(await fetchUser());
4 │ });

ℹ Svelte calls the value this function returns when the store is no longer used. An async function returns a promise, and calling a promise throws an error.

ℹ Make the function synchronous, start the async work inside it, and call set() when the result is ready.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { readable } from "svelte/store";
const time = readable(new Date(), async function (set) {
set(await fetchTime());
});
code-block.js:2:35 lint/nursery/noSvelteAsyncStore ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ This async function is passed to readable().

1 │ import { readable } from "svelte/store";
> 2 │ const time = readable(new Date(), async function (set) {
│ ^^^^^
3 │ set(await fetchTime());
4 │ });

ℹ Svelte calls the value this function returns when the store is no longer used. An async function returns a promise, and calling a promise throws an error.

ℹ Make the function synchronous, start the async work inside it, and call set() when the result is ready.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { derived } from "svelte/store";
const profile = derived(user, async ($user) => await fetchProfile($user));
code-block.js:2:31 lint/nursery/noSvelteAsyncStore ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ This async function is passed to derived().

1 │ import { derived } from "svelte/store";
> 2 │ const profile = derived(user, async ($user) => await fetchProfile($user));
│ ^^^^^
3 │

ℹ Svelte uses the value this function returns, either to clean up or as the value of the store. An async function returns a promise instead, so the cleanup never runs or the store holds the promise.

ℹ Make the function synchronous, start the async work inside it, and call set() when the result is ready.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { derived, writable } from "svelte/store";
const user = writable(null, (set) => {
fetchUser().then(set);
});
const profile = derived(user, ($user, set) => {
fetchProfile($user).then(set);
});