How to Load Data from Database in Remix Framework
In Remix, load data from a database by creating an async
loader function that fetches data on the server before rendering. Use useLoaderData() in your component to access this data safely and efficiently.Syntax
The main parts to load data from a database in Remix are:
- loader: An async function exported from your route file that fetches data from the database.
- useLoaderData(): A React hook to access the data returned by the loader inside your component.
The loader runs on the server before rendering, so you can safely query your database there.
typescript
import { json } from '@remix-run/node'; import { useLoaderData } from '@remix-run/react'; export async function loader() { const data = await fetchDataFromDatabase(); return json(data); } export default function Component() { const data = useLoaderData(); return <div>{JSON.stringify(data)}</div>; }
Example
This example shows how to load a list of users from a database using a loader and display them in a Remix route component.
typescript
import { json } from '@remix-run/node'; import { useLoaderData } from '@remix-run/react'; // Simulated database query function async function getUsers() { return [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]; } export async function loader() { const users = await getUsers(); return json(users); } export default function Users() { const users = useLoaderData(); return ( <main> <h1>User List</h1> <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> </main> ); }
Output
<main>
<h1>User List</h1>
<ul>
<li>Alice</li>
<li>Bob</li>
<li>Charlie</li>
</ul>
</main>
Common Pitfalls
- Trying to fetch data directly inside the component instead of using a
loadercauses data to load on the client, losing Remix's server-side benefits. - Not returning data wrapped in
json()from the loader can cause errors or unexpected results. - Forgetting to use
awaitwhen calling async database functions inside the loader leads to unresolved promises. - Accessing database code directly in components breaks Remix's data loading pattern and can expose secrets to the client.
typescript
/* Wrong way: fetching data inside component (runs on client) */ import { useEffect, useState } from 'react'; export default function Users() { const [users, setUsers] = useState([]); useEffect(() => { fetch('/api/users') .then(res => res.json()) .then(data => setUsers(data)); }, []); return <div>{JSON.stringify(users)}</div>; } /* Right way: use loader for server-side data fetching */ import { json } from '@remix-run/node'; import { useLoaderData } from '@remix-run/react'; async function getUsersFromDatabase() { // Implement your database fetching logic here return [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]; } export async function loader() { const users = await getUsersFromDatabase(); return json(users); } export default function Users() { const users = useLoaderData(); return <div>{JSON.stringify(users)}</div>; }
Quick Reference
- loader: async function to fetch data on server
- json(): wraps data for Remix response
- useLoaderData(): hook to access loader data in component
- Always keep database calls inside
loaderfor security and performance
Key Takeaways
Use an async loader function to fetch database data on the server in Remix.
Return data wrapped in json() from the loader for proper response formatting.
Access loader data in your component with useLoaderData() hook.
Avoid fetching data directly inside components to keep server-side benefits.
Keep database logic inside loaders to protect secrets and improve performance.