How to Use Drizzle with Remix: Setup and Example
To use
drizzle-orm with Remix, install Drizzle packages, set up your database connection in a Remix loader or action, and use Drizzle's query builder to interact with your database. You then export functions to run queries server-side and call them in Remix loaders or actions for data fetching and mutations.Syntax
Here is the basic syntax to set up Drizzle ORM with Remix:
- Import Drizzle and your database client (e.g.,
pgfor PostgreSQL). - Create a database connection using the client.
- Initialize Drizzle with the connection.
- Define your tables and queries using Drizzle's schema and query builder.
- Use Remix loaders or actions to call your Drizzle query functions server-side.
typescript
import { createClient } from '@libsql/client'; import { drizzle } from 'drizzle-orm/libsql'; // Create a database client const client = createClient({ url: 'your-database-url' }); // Initialize Drizzle ORM const db = drizzle(client); // Define a query function export async function getUsers() { return await db.select().from('users'); } // In Remix loader export async function loader() { const users = await getUsers(); return { users }; }
Example
This example shows a simple Remix loader fetching users from a SQLite database using Drizzle ORM. It demonstrates setting up the database, defining a table, and querying data in a loader.
typescript
import { json } from '@remix-run/node'; import { drizzle } from 'drizzle-orm/sqlite3'; import sqlite3 from 'sqlite3'; import { eq } from 'drizzle-orm'; import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; import { useLoaderData } from '@remix-run/react'; // Define users table schema const users = sqliteTable('users', { id: integer('id').primaryKey().autoincrement(), name: text('name'), }); // Open SQLite database const db = drizzle(new sqlite3.Database('./mydb.sqlite')); // Loader to fetch all users export async function loader() { const allUsers = await db.select().from(users); return json({ users: allUsers }); } // React component to display 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>
</ul>
</main>
Common Pitfalls
Common mistakes when using Drizzle with Remix include:
- Trying to use Drizzle client-side instead of only server-side in loaders or actions.
- Not properly initializing the database connection before queries.
- Forgetting to await async database calls, causing unresolved promises.
- Mixing Drizzle schema definitions with incompatible database clients.
Always keep Drizzle usage server-only and ensure your database client matches your database type.
typescript
/* Wrong: Using Drizzle client in React component (client-side) */ import { drizzle } from 'drizzle-orm'; const db = drizzle(client); function Users() { const users = db.select().from('users'); // โ This is async and server-only return <div>{users.length}</div>; } /* Right: Use Drizzle in loader and pass data to component */ export async function loader() { const users = await db.select().from('users'); return { users }; } function Users() { const { users } = useLoaderData(); return <div>{users.length}</div>; }
Quick Reference
Tips for using Drizzle with Remix:
- Always initialize Drizzle with a server-side database client.
- Use Remix loaders and actions to run Drizzle queries asynchronously.
- Define your database schema with Drizzle's schema helpers for type safety.
- Pass data from loaders to React components via
useLoaderData(). - Handle errors in loaders/actions to avoid crashes.
Key Takeaways
Use Drizzle ORM only in Remix loaders or actions to keep database logic server-side.
Initialize Drizzle with the correct database client matching your database type.
Define your tables with Drizzle schema helpers for clear and type-safe queries.
Always await Drizzle async calls and pass data to components via useLoaderData.
Avoid using Drizzle directly in React components to prevent runtime errors.