Most components display data from an API; the await block handles the three states declaratively.
The `{#await}` block renders a promise's three states:
{#await promise}
<p>Loading...</p>
{:then user}
<p>{user.name}</p>
{:catch error}
<p>Failed: {error.message}</p>
{/await}Short forms exist: {#await promise then value} skips the loading branch, and {:catch} can be omitted.
A common pattern stores the promise in state, or derives it from other state, so it reloads automatically:
let id = $state(1);
let userPromise = $derived(fetch(`/api/users/${id}`).then((r) => r.json()));When id changes a new promise is created and the block shows the pending branch again. The block only renders the result of the latest promise, so a slow older response can't overwrite a newer one.
Keep in mind:
fetchonly rejects on network errors; checkres.okand throw for HTTP errors so{:catch}runs.- During server-side rendering only the pending branch is rendered for unresolved promises; in SvelteKit, load data in
loadfunctions instead so pages render with data on the server. - For mutations (POST), call
fetchin event handlers, not in derived values.
Svelte 5.36+ also has an experimental mode allowing await directly in markup and deriveds, covered in the expert lessons.
Example
<script>
let id = $state(1);
async function getUser(id) {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`); // make 404 reject
return res.json();
}
let user = $derived(getUser(id)); // new promise whenever id changes
</script>
<button onclick={() => id--} disabled={id === 1}>prev</button>
<button onclick={() => id++}>next</button>
{#await user}
<p>Loading user {id}...</p>
{:then u}
<h2>{u.name}</h2><p>{u.email}</p>
{:catch err}
<p class="error">Could not load: {err.message}</p>
{/await}Remember
{#await p}...{:then v}...{:catch e}{/await}handles loading, success and error- Derive the promise from state to refetch when inputs change
- Throw on non-OK responses so the catch branch runs
Watch out for
- Assuming fetch rejects on HTTP 404/500; it resolves, so check
res.ok.