---
title: 'React Router'
description: 'Run bknd inside React Router'
---
import InstallBknd from '/snippets/install-bknd.mdx';
## Installation
To get started with React Router and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
Create a new React Router CLI starter project by running the following command:
```sh
npx bknd create -i react-router
```
Create a new React Router project by following the [official guide](https://reactrouter.com/start/framework/installation), and then install bknd as a dependency:
## Configuration
Now create a `bknd.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
```typescript bknd.config.ts
import type { ReactRouterBkndConfig } from "bknd/adapter/react-router";
export default {
connection: {
url: "file:data.db"
},
} satisfies ReactRouterBkndConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `ReactRouterBkndConfig` type extends the `BkndConfig` type with the following additional properties:
```typescript
type ReactRouterEnv = NodeJS.ProcessEnv;
type ReactRouterFunctionArgs = {
request: Request;
};
export type ReactRouterBkndConfig = FrameworkBkndConfig;
```
## Serve the API
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configurationfrom the `bknd.config.ts` file:
```ts app/bknd.ts
import { type ReactRouterBkndConfig, getApp as getBkndApp } from "bknd/adapter/react-router";
import config from "../bknd.config";
export { config };
// you may adjust this function depending on your runtime environment.
// e.g. when deploying to cloudflare workers, you'd want the FunctionArgs to be passed in
// to resolve environment variables
export async function getApp() {
return await getBkndApp(config, process.env as any);
}
export async function getApi(
args?: { request: Request },
opts?: { verify?: boolean }
) {
const app = await getApp();
if (opts?.verify) {
const api = app.getApi({ headers: args?.request.headers });
await api.verifyAuth();
return api;
}
return app.getApi();
}
```
For more information about the connection object, refer to the [Database](/usage/database) guide.
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();
return app.fetch(args.request);
};
export const loader = handler;
export const action = handler;
```
## Enabling the Admin UI
Create a new splat route file at `app/routes/admin.$.tsx`:
```tsx app/routes/admin.$.tsx
import { lazy, Suspense, useSyncExternalStore } from "react";
import { type LoaderFunctionArgs, useLoaderData } from "react-router";
import { getApi } from "~/bknd";
const Admin = lazy(() => import("bknd/ui").then((mod) => ({ default: mod.Admin })));
import "bknd/dist/styles.css";
export const loader = async (args: LoaderFunctionArgs) => {
const api = await getApi(args, { verify: true });
return {
user: api.getUser(),
};
};
export default function AdminPage() {
const { user } = useLoaderData();
// derived from https://github.com/sergiodxa/remix-utils
// @ts-ignore
const hydrated = useSyncExternalStore(() => {}, () => true, () => false);
if (!hydrated) return null;
return (
);
}
```
## Example usage of the API
You can use the `getApi` helper function we've already set up to fetch and mutate:
```tsx app/routes/_index.tsx
import { useLoaderData, type LoaderFunctionArgs } from "react-router";
import { getApi } from "~/bknd";
export const loader = async (args: LoaderFunctionArgs) => {
// use authentication from request
const api = await getApi(args, { verify: true });
const { data } = await api.data.readMany("todos");
return { data, user: api.getUser() };
};
export default function Index() {
const { data, user } = useLoaderData();
return (