---
title: "Solid Start"
description: "Run bknd inside Solid Start"
tags: ["documentation"]
---

## Installation

To get started with Solid Start and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter.

Create a new Solid Start project by following the [official guide](https://docs.solidjs.com/solid-start/getting-started), and then install bknd as a dependency:

<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>

```bash tab="npm"
npm install bknd
```

```bash tab="pnpm"
pnpm install bknd
```

```bash tab="yarn"
yarn add bknd
```

```bash tab="bun"
bun add bknd
```

</Tabs>

## Configuration

<Callout type="warning">
  When run with Node.js, a version of 22 (LTS) or higher is required. Please
  verify your version by running `node -v`, and
  [upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>

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 title="bknd.config.ts"
import type { SolidStartBkndConfig } from "bknd/adapter/solid-start";
import { em, entity, text, boolean } from "bknd";
import { secureRandomString } from "bknd/utils";

const schema = em({
  todos: entity("todos", {
    title: text(),
    done: boolean(),
  }),
});

// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd" {
  interface DB extends Database {}
}

export default {
  connection: {
    url: "file:data.db",
  },
  options: {
    // the seed option is only executed if the database was empty
    seed: async (ctx) => {
      // create some entries
      await ctx.em.mutator("todos").insertMany([
        { title: "Learn bknd", done: true },
        { title: "Build something cool", done: false },
      ]);

      // and create a user
      await ctx.app.module.auth.createUser({
        email: "test@bknd.io",
        password: "12345678",
      });
    },
  },
  config: {
    data: schema.toJSON(),
    auth: {
      enabled: true,
      jwt: {
        secret: secureRandomString(32),
      },
    },
  },
  // please run `bun bknd copy-assets --out public/admin` to copy the admin assets into the public directory
  // alternatively add this as a postinstall script in your package.json like this:
  // "postinstall": "bknd copy-assets --out public/admin"
  adminOptions: {
    adminBasepath: "/admin",
    assetsPath: "/admin/", // trailing slash is important
  },
} satisfies SolidStartBkndConfig;
```

See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `SolidStartBkndConfig` type extends the `BkndConfig` type with the following additional properties:

```typescript
export type SolidStartBkndConfig<Env = SolidStartEnv> = RuntimeBkndConfig<Env>;
```

## Serve the API and Admin UI

The Solid Start adapter uses middleware to handle API requests and serve the Admin UI. Create a `src/middleware/index.ts` file:

```ts title="src/middleware/index.ts"
import { createMiddleware } from "@solidjs/start/middleware";
import config from "../../bknd.config";
import { serve } from "bknd/adapter/solid-start";

const handler = serve(config);

export default createMiddleware({
  onRequest: async (event) => {
    const url = new URL(event.request.url);
    const pathname = url.pathname;

    if (pathname.startsWith("/api") || pathname !== "/") {
      const res = await handler(event.request);

      if (res && res.status !== 404) {
        return res;
      }
    }
  },
});
```

### Update the app config (Solid Start v1 based on vinxi)

Add the following to your `app.config.ts` file:

```ts title="app.config.ts"
import { defineConfig } from "@solidjs/start/config";

const app = defineConfig({
  // ... your existing config
  middleware: "src/middleware/index.ts",
  // ... your existing config
});

export default app;
```

### Update the vite config (Solid Start v2)

Add the following to your `vite.config.ts` file:

```ts title="vite.config.ts"
import { defineConfig } from "vite";
import solid from "vite-plugin-solid";
import { solidStart } from "@solidjs/start/vite";

export default defineConfig({
  plugins: [
    solid(),
    solidStart({
      middleware: "./src/middleware/index.ts",
    }),
  ],
});
```


<Callout type="success">
  You can visit https://localhost:3000/admin to see the admin UI. Additionally you can create more todos as you explore the admin UI.
</Callout>

Create a helper file to instantiate the bknd instance and retrieve the API, importing the configuration from the `bknd.config.ts` file:


```ts title="src/lib/bknd.ts"
import { getApp as getBkndApp } from "bknd/adapter/solid-start";
import bkndConfig from "../../bknd.config";
import type { App } from "bknd";

export const getApp = async () => {
  return await getBkndApp(bkndConfig);
};

export async function getApi({
  headers,
  verify,
}: {
  verify?: boolean;
  headers?: Headers;
}) {
  const app = await getApp();

  if (verify) {
    const api = app.getApi({ headers });
    await api.verifyAuth();
    return api;
  }

  return app.getApi();
};
```
## Example usage of the API

You can use the `getApi` helper function we've already set up to fetch and mutate in static pages and server components:

```tsx title="src/routes/index.tsx"
import { getApi } from "~/lib/bknd";
import { query, createAsync } from "@solidjs/router";

export const getTodo = async () => {
  "use server"
  const api = await getApi({});
  const limit = 5;
  const todos = await api.data.readMany("todos");
  const total = todos.body.meta.total as number;
  return { total, todos: todos as unknown as Todo[], limit };
};

const getTodosFromServer = query(async () => await getTodo(), "getTodosFromServer");

export default function Home() {
  const data = createAsync(() => getTodosFromServer());

  return (
    <ul>
     <For each={data()}>
      {(todo) => <li>{todo.title}</li>}
     </For>
    </ul>
  );
}
```

## Using authentication

When using authentication, you'll need to pass the headers to the `getApi` function to verify the user is authenticated.

```tsx title="src/routes/auth.tsx"
import { createResource, Suspense } from "solid-js";
import { A } from "@solidjs/router";
import { getRequestEvent } from "solid-js/web";
import { getApi } from "~/lib/bknd";

export const getUser = async () => {
  "use server"
  const request = getRequestEvent()?.request;
  const api = await getApi({ verify: true, headers: request?.headers });
  return api.getUser();
}

export default function Auth() {
  const [data] = createResource(async () => {
    const user = await getUser()
    return { user };
  }, {
    initialValue: {
      user: null
    }
  });

  return (
    <div class="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
      <main class="flex flex-col gap-8 row-start-2 items-center sm:items-start">
        <div class="flex flex-row items-center ">
          <img
            class="dark:invert size-18"
            src="/solid.svg"
            alt="Solid logo"
          />
          <div class="ml-3.5 mr-2 opacity-70">&amp;</div>
          <img
            class="dark:invert"
            src="/bknd.svg"
            alt="bknd logo"
            width={183}
            height={59}
          />
        </div>

        <Suspense fallback={<p>Loading...</p>}>
          <div>
            {data()?.user ? (
              <>
                Logged in as {data()?.user?.email}.
                <A
                  class="underline"
                  target="_self"
                  href={"/api/auth/logout"}
                >
                  Logout
                </A>
              </>
            ) : (
              <div class="flex flex-col gap-1">
                <p>
                  Not logged in.
                  <A
                    class="underline"
                    target="_self"
                    href={"/admin/auth/login"}
                  >
                    Login
                  </A>
                </p>
                <p class="text-xs opacity-50">
                  Sign in with:
                  <b>
                    <code>test@bknd.io</code>
                  </b>
                  /
                  <b>
                    <code>12345678</code>
                  </b>
                </p>
              </div>
            )}
          </div>
        </Suspense>
      </main>
    </div>
  );
}
```


## Tips

Use `target="_self"` on links, anytime your traversing to an external route (like `/api/auth/logout` which are handled by bknd's middleware) to prevent solid router from intercepting the link.
```jsx
<A href="/api/auth/logout" target="_self">
  Logout
</A>
```