# Better Auth (with Astro) (/docs/guides/authentication/better-auth/astro) > For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL. Learn how to use Prisma ORM in an Astro app with Better Auth Location: Guides > Authentication > Better Auth > Better Auth (with Astro) > [!NOTE] > This guide uses Prisma ORM 7 > > The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see [Create a new app with PostgreSQL](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add Prisma ORM to an existing PostgreSQL database](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is not available yet: Better Auth's `prismaAdapter` requires Prisma Client, which Prisma ORM 8 replaces with the `@prisma/orm-postgres` runtime. ## Introduction [#introduction] [Better Auth](https://better-auth.com/) is an open-source authentication library for web apps. It's written in TypeScript, can be extended with plugins, and supports multiple database adapters, including Prisma. In this guide, you'll wire Better Auth into a brand-new [Astro](https://astro.build/) app and persist users in a [Prisma Postgres](https://prisma.io/postgres) database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/betterauth-astro). ## Prerequisites [#prerequisites] * [Node.js 22.12+ on 22.x or 24+](https://nodejs.org) * Basic familiarity with Astro and Prisma ## 1. Set up your project [#1-set-up-your-project] Create a new Astro project: #### bun ```bash bunx create-astro betterauth-astro-prisma ``` #### pnpm ```bash pnpm create astro betterauth-astro-prisma ``` #### yarn ```bash yarn create astro betterauth-astro-prisma ``` #### npm ```bash npm create astro@latest betterauth-astro-prisma ``` > [!NOTE] > * *How would you like to start your new project?* `Use minimal (empty) template ` > * *Install dependencies? (recommended)* `Yes` > * *Initialize a new git repository? (optional)* `Yes` Navigate to the project directory: ```bash cd betterauth-astro-prisma ``` These selections will create a minimal Astro project with TypeScript for type safety. ## 2. Set up Prisma [#2-set-up-prisma] Next, you'll add Prisma to your project to manage your database. ### 2.1. Install Prisma and dependencies [#21-install-prisma-and-dependencies] Install the necessary Prisma packages: #### bun ```bash bun add prisma@prev tsx @types/pg --dev ``` #### pnpm ```bash pnpm add prisma@prev tsx @types/pg --save-dev ``` #### yarn ```bash yarn add prisma@prev tsx @types/pg --dev ``` #### npm ```bash npm install prisma@prev tsx @types/pg --save-dev ``` #### bun ```bash bun add @prisma/client@7 @prisma/adapter-pg dotenv pg ``` #### pnpm ```bash pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg ``` #### yarn ```bash yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg ``` #### npm ```bash npm install @prisma/client@7 @prisma/adapter-pg dotenv pg ``` > [!NOTE] > If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers). Once installed, initialize Prisma in your project: #### bun ```bash bunx --bun prisma init --output ../prisma/generated ``` #### pnpm ```bash pnpm prisma init --output ../prisma/generated ``` #### yarn ```bash yarn prisma init --output ../prisma/generated ``` #### npm ```bash npx prisma init --output ../prisma/generated ``` > [!NOTE] > `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string. This will create: * A `prisma` directory with a `schema.prisma` file * A `.env` file containing a local `DATABASE_URL` at the project root * A `prisma.config.ts` file for configuring Prisma * An `output` directory for the generated Prisma Client as `prisma/generated` Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output: #### bun ```bash bunx create-db ``` #### pnpm ```bash pnpm dlx create-db ``` #### yarn ```bash yarn dlx create-db ``` #### npm ```bash npx create-db ``` ### 2.2. Configure Prisma to load environment variables [#22-configure-prisma-to-load-environment-variables] To get access to the variables in the `.env` file, update your `prisma.config.ts` to import `dotenv`: ```ts title="prisma.config.ts" showLineNumbers import "dotenv/config"; // [!code ++] import { defineConfig, env } from "prisma/config"; export default defineConfig({ schema: "prisma/schema.prisma", migrations: { path: "prisma/migrations", }, engine: "classic", datasource: { url: env("DATABASE_URL"), }, }); ``` ### 2.3. Generate the Prisma Client [#23-generate-the-prisma-client] Run the following command to generate the Prisma Client: #### bun ```bash bunx prisma generate ``` #### pnpm ```bash pnpm prisma generate ``` #### yarn ```bash yarn prisma generate ``` #### npm ```bash npx prisma generate ``` ### 2.4. Set up a global Prisma client [#24-set-up-a-global-prisma-client] In the `src` directory, create a `lib` folder and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance. ```bash mkdir -p src/lib touch src/lib/prisma.ts ``` Set up the Prisma client like this: ```ts title="src/lib/prisma.ts" import { PrismaClient } from "../../prisma/generated/client"; import { PrismaPg } from "@prisma/adapter-pg"; const adapter = new PrismaPg({ connectionString: import.meta.env.DATABASE_URL, }); const prisma = new PrismaClient({ adapter, }); export default prisma; ``` > [!WARNING] > We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently. > > If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections. ## 3. Set up Better Auth [#3-set-up-better-auth] Next, add Better Auth to handle sign-up, sign-in, and sessions. ### 3.1. Install and configure Better Auth [#31-install-and-configure-better-auth] First, install the Better Auth core package: #### bun ```bash bun add better-auth ``` #### pnpm ```bash pnpm add better-auth ``` #### yarn ```bash yarn add better-auth ``` #### npm ```bash npm install better-auth ``` Next, generate a secure secret that Better Auth will use to sign authentication tokens. This ensures your tokens cannot be tampered with. #### bun ```bash bunx @better-auth/cli@latest secret ``` #### pnpm ```bash pnpm dlx @better-auth/cli@latest secret ``` #### yarn ```bash yarn dlx @better-auth/cli@latest secret ``` #### npm ```bash npx @better-auth/cli@latest secret ``` Copy the generated secret and add it, along with your application's URL, to your `.env` file: ```bash title=".env" # Better Auth BETTER_AUTH_SECRET=your-generated-secret # [!code ++] BETTER_AUTH_URL=http://localhost:4321 # [!code ++] # Prisma DATABASE_URL="your-database-url" ``` > [!NOTE] > Astro's default development server runs on port `4321`. If your application runs on a different port, update the `BETTER_AUTH_URL` accordingly. Now, create a configuration file for Better Auth. In the `src/lib` directory, create an `auth.ts` file: ```bash touch src/lib/auth.ts ``` In this file, you'll configure Better Auth to use the Prisma adapter, which allows it to persist user and session data in your database. You will also enable email and password authentication. ```ts title="src/lib/auth.ts" import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import prisma from "./prisma"; export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql", }), emailAndPassword: { enabled: true, }, }); ``` Better Auth also supports other sign-in methods like social logins (Google, GitHub, etc.), which you can explore in their [email and password documentation](https://www.better-auth.com/docs/authentication/email-password). ### 3.2. Add Better Auth models to your schema [#32-add-better-auth-models-to-your-schema] Better Auth provides a CLI command to automatically add the necessary authentication models (`User`, `Session`, `Account`, and `Verification`) to your `schema.prisma` file. Run the following command: #### bun ```bash bunx @better-auth/cli generate ``` #### pnpm ```bash pnpm dlx @better-auth/cli generate ``` #### yarn ```bash yarn dlx @better-auth/cli generate ``` #### npm ```bash npx @better-auth/cli generate ``` > [!NOTE] > It will ask for confirmation to overwrite your existing Prisma schema. Select `y`. This will add the following models: ```prisma model User { id String @id name String email String emailVerified Boolean image String? createdAt DateTime updatedAt DateTime sessions Session[] accounts Account[] @@unique([email]) @@map("user") } model Session { id String @id expiresAt DateTime token String createdAt DateTime updatedAt DateTime ipAddress String? userAgent String? userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([token]) @@map("session") } model Account { id String @id accountId String providerId String userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) accessToken String? refreshToken String? idToken String? accessTokenExpiresAt DateTime? refreshTokenExpiresAt DateTime? scope String? password String? createdAt DateTime updatedAt DateTime @@map("account") } model Verification { id String @id identifier String value String expiresAt DateTime createdAt DateTime? updatedAt DateTime? @@map("verification") } ``` ### 3.3. Migrate the database [#33-migrate-the-database] With the new models in your schema, you need to update your database. Run a migration to create the corresponding tables: #### bun ```bash bunx prisma migrate dev --name add-auth-models ``` #### pnpm ```bash pnpm prisma migrate dev --name add-auth-models ``` #### yarn ```bash yarn prisma migrate dev --name add-auth-models ``` #### npm ```bash npx prisma migrate dev --name add-auth-models ``` #### bun ```bash bunx prisma generate ``` #### pnpm ```bash pnpm prisma generate ``` #### yarn ```bash yarn prisma generate ``` #### npm ```bash npx prisma generate ```
## 4. Set up the API routes [#4-set-up-the-api-routes] Better Auth needs an API endpoint to handle authentication requests like sign-in, sign-up, and sign-out. You'll create a catch-all API route in Astro to handle all requests sent to `/api/auth/[...all]`. In the `src/pages` directory, create an `api/auth` folder structure and a `[...all].ts` file inside it: ```bash mkdir -p src/pages/api/auth touch 'src/pages/api/auth/[...all].ts' ``` Add the following code to the newly created `[...all].ts` file. This code uses the Better Auth handler to process authentication requests. ```ts title="src/pages/api/auth/[...all].ts" import { auth } from "../../../lib/auth"; import type { APIRoute } from "astro"; export const prerender = false; // Not needed in 'server' mode export const ALL: APIRoute = async (ctx) => { return auth.handler(ctx.request); }; ``` Next, you'll need a client-side utility to interact with these endpoints from your Astro pages. In the `src/lib` directory, create an `auth-client.ts` file: ```bash touch src/lib/auth-client.ts ``` Add the following code, which creates the client functions you'll use in your UI: ```ts title="src/lib/auth-client.ts" import { createAuthClient } from "better-auth/client"; export const authClient = createAuthClient(); export const { signIn, signUp, signOut, useSession } = authClient; ``` ## 5. Configure TypeScript definitions [#5-configure-typescript-definitions] In the `src` directory, create an `env.d.ts` file to provide TypeScript definitions for environment variables and Astro locals: ```bash touch src/env.d.ts ``` Add the following type definitions: ```ts title="src/env.d.ts" /// declare namespace App { interface Locals { user: import("better-auth").User | null; session: import("better-auth").Session | null; } } interface ImportMetaEnv { readonly DATABASE_URL: string; } interface ImportMeta { readonly env: ImportMetaEnv; } ``` ## 6. Set up authentication middleware [#6-set-up-authentication-middleware] In the `src` directory, create a `middleware.ts` file to check authentication status on every request. This will make the user and session data available to all your pages. ```bash touch src/middleware.ts ``` Add the following code: ```ts title="src/middleware.ts" import { auth } from "./lib/auth"; import { defineMiddleware } from "astro:middleware"; export const onRequest = defineMiddleware(async (context, next) => { context.locals.user = null; context.locals.session = null; const isAuthed = await auth.api.getSession({ headers: context.request.headers, }); if (isAuthed) { context.locals.user = isAuthed.user; context.locals.session = isAuthed.session; } return next(); }); ``` ## 7. Set up your pages [#7-set-up-your-pages] Next, build the user interface for authentication. In the `src/pages` directory, create the following folder structure: * `sign-up/index.astro` * `sign-in/index.astro` * `dashboard/index.astro` ```bash mkdir -p src/pages/{sign-up,sign-in,dashboard} touch src/pages/{sign-up,sign-in,dashboard}/index.astro ``` ### 7.1. Sign up page [#71-sign-up-page] This page allows new users to create an account. Start with the basic HTML structure in `src/pages/sign-up/index.astro`. ```html title="src/pages/sign-up/index.astro" --- export const prerender = false; --- Sign Up

Sign Up

``` Add a form with input fields for name, email, and password. This form will collect the user's registration information. ```html title="src/pages/sign-up/index.astro" --- export const prerender = false; --- Sign Up

Sign Up

// [!code ++] // [!code ++] // [!code ++] // [!code ++] // [!code ++]
// [!code ++]

Already have an account? Sign in here.

// [!code ++]
``` Now add a script to handle form submission. Import the `authClient` and add an event listener to the form that prevents the default submission behavior, extracts the form data, and calls the Better Auth sign-up method. ```html title="src/pages/sign-up/index.astro" --- export const prerender = false; --- Sign Up

Sign Up

Already have an account? Sign in here.

// [!code ++] ``` Finally, add a server-side check to redirect authenticated users away from this page. If a user is already signed in, they should be redirected to the dashboard instead. ```html title="src/pages/sign-up/index.astro" --- export const prerender = false; if (Astro.locals.user?.id) return Astro.redirect("/dashboard"); // [!code ++] --- Sign Up

Sign Up

Already have an account? Sign in here.

``` ### 7.2. Sign in page [#72-sign-in-page] This page allows existing users to authenticate. Start with the basic HTML structure in `src/pages/sign-in/index.astro`. ```html title="src/pages/sign-in/index.astro" --- export const prerender = false; --- Sign In

Sign In

``` Add a form with input fields for email and password. This form will collect the user's credentials. ```html title="src/pages/sign-in/index.astro" --- export const prerender = false; --- Sign In

Sign In

// [!code ++] // [!code ++] // [!code ++] // [!code ++]
// [!code ++]

Don't have an account? Sign up here.

// [!code ++]
``` Now add a script to handle form submission. Import the `authClient` and add an event listener that prevents default submission, extracts the form data, and calls the Better Auth sign-in method. ```html title="src/pages/sign-in/index.astro" --- export const prerender = false; --- Sign In

Sign In

Don't have an account? Sign up here.

// [!code ++] ``` Finally, add a server-side check to redirect authenticated users away from this page. If a user is already signed in, they should be redirected to the dashboard instead. ```html title="src/pages/sign-in/index.astro" --- export const prerender = false; if (Astro.locals.user?.id) return Astro.redirect("/dashboard"); // [!code ++] --- Sign In

Sign In

Don't have an account? Sign up here.

``` ### 7.3. Dashboard page [#73-dashboard-page] This is the protected page for authenticated users. Start with the basic HTML structure in `src/pages/dashboard/index.astro`. ```html title="src/pages/dashboard/index.astro" --- export const prerender = false; --- Dashboard

Dashboard

``` Add a server-side check to protect this route. If the user is not authenticated, redirect them to the sign-in page. ```html title="src/pages/dashboard/index.astro" --- export const prerender = false; if (!Astro.locals.user?.id) return Astro.redirect("/sign-in"); // [!code ++] --- Dashboard

Dashboard

``` Now display the authenticated user's information. The `Astro.locals.user` object contains the user data that was set by the middleware. ```html title="src/pages/dashboard/index.astro" --- export const prerender = false; if (!Astro.locals.user?.id) return Astro.redirect("/sign-in"); --- Dashboard

Dashboard

{JSON.stringify(Astro.locals.user, null, 2)}
// [!code ++]
``` Finally, add a sign-out button. Import the `authClient` and add a button that calls the sign-out method, allowing the user to log out and be redirected to the sign-in page. ```html title="src/pages/dashboard/index.astro" --- export const prerender = false; if (!Astro.locals.user?.id) return Astro.redirect("/sign-in"); --- Dashboard

Dashboard

{JSON.stringify(Astro.locals.user, null, 2)}
// [!code ++]
// [!code ++] ``` ### 7.4. Home page [#74-home-page] Finally, update the home page to link to the sign-up, sign-in, and dashboard pages. Replace the contents of `src/pages/index.astro` with the following: ```html title="src/pages/index.astro" --- export const prerender = false; --- Better Auth + Astro + Prisma

Better Auth + Astro + Prisma

{ Astro.locals.user ? (

Welcome back, {Astro.locals.user.name}!

Go to Dashboard
) : (
Sign Up Sign In
) }
``` ## 8. Test it out [#8-test-it-out] Your application is now fully configured. 1. Start the development server to test it: #### bun ```bash bun run dev ``` #### pnpm ```bash pnpm run dev ``` #### yarn ```bash yarn dev ``` #### npm ```bash npm run dev ``` 2. Navigate to `http://localhost:4321` in your browser. You should see the home page with "Sign Up" and "Sign In" links. 3. Click on **Sign Up**, create a new account, and you should be redirected to the dashboard. You can then sign out and sign back in. 4. To view the user data directly in your database, you can use Prisma Studio. #### bun ```bash bunx prisma studio ``` #### pnpm ```bash pnpm prisma studio ``` #### yarn ```bash yarn prisma studio ``` #### npm ```bash npx prisma studio ``` 5. This will open a new tab in your browser where you can see the `User`, `Session`, and `Account` tables and their contents. > [!TIP] > You now have a working authentication system built with Better Auth, Prisma, and Astro. ## Next steps [#next-steps] * Add support for social login or magic links * Implement password reset and email verification * Add user profile and account management pages * Deploy to Vercel or Netlify and secure your environment variables * Extend your Prisma schema with custom application models ## Further reading [#further-reading] * [Better Auth documentation](https://www.better-auth.com/docs) * [Prisma documentation](https://www.prisma.io/docs/orm/v7) * [Astro documentation](https://astro.build/docs) ## Related pages - [`Better Auth (with Next.js)`](https://www.prisma.io/docs/guides/authentication/better-auth/nextjs): Learn how to use Prisma ORM in a Next.js app with Better Auth