---
title: 'Remix'
description: 'Run bknd inside Remix'
---
import InstallBknd from '/snippets/install-bknd.mdx';

## Installation
To get started with Remix and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:

<Tabs>
   <Tab title="CLI Starter">
      Create a new Remix CLI starter project by running the following command:

      ```sh
      npx bknd create -i remix
      ```
   </Tab>
   <Tab title="Manual">
      Create a new Remix project by following the [official guide](https://remix.run/docs/en/main/other-api/create-remix), and then install bknd as a dependency:

      <InstallBknd />
   </Tab>
</Tabs>


## Serve the API
Since Remix doesn't support middleware yet, we need a helper file to initialize the App to import from. Create a new file at `app/bknd.ts`:
```ts app/bknd.ts
import { type RemixBkndConfig, getApp as getBkndApp } from "bknd/adapter/remix";

const config = {
   connection: {
      url: "file:data.db"
   }
} as const satisfies RemixBkndConfig;

export async function getApp(args?: { request: Request }) {
   return await getBkndApp(config, args);
}

export async function getApi(args?: { request: Request }) {
   const app = await getApp(args);
   if (args) {
      const api = app.getApi(args.request);
      await api.verifyAuth();
      return api;
   }

   return app.getApi();
}
```

Create a new api splat route file at `app/routes/api.$.ts`:
```ts app/routes/api.$.ts
import { getApp } from "~/bknd";

const handler = async (args: { request: Request }) => {
   const app = await getApp(args);
   return app.fetch(args.request);
};

export const loader = handler;
export const action = handler;
```
For more information about the connection object, refer to the [Database](/usage/database) guide.

Now make sure that you wrap your root layout with the `ClientProvider` so that all components share the same context. Also add the user context to both the `Outlet` and the provider:
```tsx app/root.tsx
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { useLoaderData, Outlet } from "@remix-run/react";
import { ClientProvider } from "bknd/client";
import { getApi } from "~/bknd";

export function Layout(props) {
   // nothing to change here, just for orientation
   return (
      <html>{/* ... */}</html>
   );
}

export const loader = async (args: LoaderFunctionArgs) => {
   const api = await getApi(args);
   return {
      user: api.getUser()
   };
};

export default function App() {
   const data = useLoaderData<typeof loader>();
   return (
      <ClientProvider user={data.user}>
         <Outlet context={data} />
      </ClientProvider>
   );
}
```

## Enabling the Admin UI
Create a new splat route file at `app/routes/admin.$.tsx`:
```tsx app/routes/admin.$.tsx
import { adminPage } from "bknd/adapter/remix";
import "bknd/dist/styles.css";

export default adminPage({
   config: {
      basepath: "/admin",
      logo_return_path: "/../",
      color_scheme: "system"
   }
});
```

## Example usage of the API
Since the API has already been constructed in the root layout, you can now use it in any page:
```tsx app/routes/_index.tsx
import { useLoaderData } from "@remix-run/react";
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { getApi } from "~/bknd";

export const loader = async (args: LoaderFunctionArgs) => {
   // use authentication from request
   const api = await getApi(args);
   const { data } = await api.data.readMany("todos");
   return { data, user: api.getUser() };
};

export default function Index() {
   const { data, user } = useLoaderData<typeof loader>();

   return (
      <div>
         <h1>Data</h1>
         <pre>{JSON.stringify(data, null, 2)}</pre>
         <h1>User</h1>
         <pre>{JSON.stringify(user, null, 2)}</pre>
      </div>
   );
}
```