Data fetching
Edit this pageThis guide provides practical examples of common data-fetching tasks in SolidStart.
Here's an example showing how to create a query and access its data with the createAsync primitive:
// src/routes/index.tsximport { For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </ul> );}// src/routes/index.jsximport { For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </ul> );}Showing loading UI
To show a loading UI during data fetching:
- Import
Suspensefromsolid-js. - Wrap your data rendering in
<Suspense>, and use thefallbackprop to show a component during data fetching.
// src/routes/index.tsximport { Suspense, For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ul> );}// src/routes/index.jsximport { Suspense, For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ul> );}Handling errors
To show a fallback UI if the data fetching fails:
- Import
ErrorBoundaryfromsolid-js. - Wrap the data rendering in
<ErrorBoundary>, and use thefallbackprop to show a component if an error occurs.
// src/routes/index.tsximport { ErrorBoundary, Suspense, For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ErrorBoundary> </ul> );}// src/routes/index.jsximport { ErrorBoundary, Suspense, For } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ErrorBoundary> </ul> );}Preloading data
To preload data before a route renders:
- Export a
routeobject with apreloadfunction. - Run your query inside the
preloadfunction. - Use the query as usual in your component.
// src/routes/index.tsximport { ErrorBoundary } from "solid-js";import { query, createAsync, type RouteDefinition } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export const route = { preload: () => getPosts(),} satisfies RouteDefinition;
export default function Page() { const post = createAsync(() => getPosts()); return ( <div> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <h1>{post().title}</h1> </ErrorBoundary> </div> );}// src/routes/index.jsximport { ErrorBoundary } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPosts = query(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json();}, "posts");
export const route = { preload: () => getPosts(),};
export default function Page() { const post = createAsync(() => getPosts()); return ( <div> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <h1>{post().title}</h1> </ErrorBoundary> </div> );}Passing parameters to queries
When creating a query that accepts parameters, define your query function to take any number of parameters:
// src/routes/posts/[id]/index.tsximport { ErrorBoundary } from "solid-js";import { query, createAsync, type RouteDefinition } from "@solidjs/router";
const getPost = query(async (id: string) => { const post = await fetch(`https://my-api.com/posts/${id}`); return await post.json();}, "post");
export const route = { preload: ({ params }) => getPost(params.id),} satisfies RouteDefinition;
export default function Page() { const postId = 1; const post = createAsync(() => getPost(postId)); return ( <div> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <h1>{post().title}</h1> </ErrorBoundary> </div> );}// src/routes/posts/[id]/index.jsximport { ErrorBoundary } from "solid-js";import { query, createAsync } from "@solidjs/router";
const getPost = query(async (id) => { const post = await fetch(`https://my-api.com/posts/${id}`); return await post.json();}, "post");
export const route = { preload: ({ params }) => getPost(params.id),};
export default function Page() { const postId = 1; const post = createAsync(() => getPost(postId)); return ( <div> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <h1>{post().title}</h1> </ErrorBoundary> </div> );}Using a database or an ORM
To safely interact with your database or ORM in a query, use a server function:
// src/routes/index.tsximport { For, ErrorBoundary } from "solid-js";import { query, createAsync, type RouteDefinition } from "@solidjs/router";import { db } from "~/lib/db";
const getPosts = query(async () => { "use server"; return await db.from("posts").select();}, "posts");
export const route = { preload: () => getPosts(),} satisfies RouteDefinition;
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </ErrorBoundary> </ul> );}// src/routes/index.jsximport { For, ErrorBoundary } from "solid-js";import { query, createAsync } from "@solidjs/router";import { db } from "~/lib/db";
const getPosts = query(async () => { "use server"; return await db.from("posts").select();}, "posts");
export const route = { preload: () => getPosts(),};
export default function Page() { const posts = createAsync(() => getPosts()); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </ErrorBoundary> </ul> );}Fetching data on the client
To fetch data only on the client, use the createResource primitive:
// src/routes/index.tsximport { createResource, ErrorBoundary, Suspense, For } from "solid-js";
export default function Page() { const [posts] = createResource(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json(); }); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ErrorBoundary> </ul> );}// src/routes/index.jsximport { createResource, ErrorBoundary, Suspense, For } from "solid-js";
export default function Page() { const [posts] = createResource(async () => { const posts = await fetch("https://my-api.com/posts"); return await posts.json(); }); return ( <ul> <ErrorBoundary fallback={<div>Something went wrong!</div>}> <Suspense fallback={<div>Loading...</div>}> <For each={posts()}>{(post) => <li>{post.title}</li>}</For> </Suspense> </ErrorBoundary> </ul> );}See the createResource API reference for more information.
Advanced Data Handling
For advanced features like automatic background re-fetching or infinite queries, you can use TanStack Query.