---
title: "Add Auth to Astro 5 with Clerk in 5 Minutes"
description: "The simplest setup for adding Clerk authentication to your Astro project, with minimal code"
canonical: "https://www.trevorlasn.com/blog/astro-and-clerk"
author: "Trevor I. Lasn"
published: "2024-12-18"
last-updated: "2026-11-08"
topics: ["Security"]
---

# Add Auth to Astro 5 with Clerk in 5 Minutes

The simplest setup for adding Clerk authentication to your Astro project, with minimal code

By Trevor I. Lasn · Published 2024-12-18 · Updated 2026-11-08 · https://www.trevorlasn.com/blog/astro-and-clerk

Authentication has always been a pain point. Either you spend weeks building a robust auth system, or you piece together various services that don't quite fit. That's why I was excited to discover how well [Astro](https://astro.build/) and [Clerk](https://clerk.com/) work together.

## Update: Clerk replaced SignedIn, SignedOut and createRouteMatcher

Two Clerk releases broke the code below. [Clerk Core 3](https://clerk.com/docs/guides/development/upgrading/upgrade-guides/core-3) (`@clerk/astro` 3.0, March 2026) removed `<SignedIn>` and `<SignedOut>`, so use `<Show when="signed-in">` and `<Show when="signed-out">` from `@clerk/astro/components` instead. [`@clerk/astro` 4.0](https://github.com/clerk/javascript/blob/main/packages/astro/CHANGELOG.md) (July 2026) removed `createRouteMatcher`, so the middleware now only runs Clerk:

```ts title="src/middleware.ts"
import { clerkMiddleware } from "@clerk/astro/server";

export const onRequest = clerkMiddleware();
```

Then protect each page in its own frontmatter:

```astro title="src/pages/dashboard.astro"
---
const { isAuthenticated, redirectToSignIn } = Astro.locals.auth();
if (!isAuthenticated) return redirectToSignIn();
---
```

The install command below now adds the `@astrojs/node` adapter that the config uses, as the [Astro quickstart](https://clerk.com/docs/astro/getting-started/quickstart) does. The free Hobby plan now includes [50,000 monthly retained users](https://clerk.com/pricing) per app, up from the 10,000 monthly active users mentioned below.

### Why Astro?

Astro's content-focused approach means I can build fast, SEO-friendly sites without shipping unnecessary JavaScript. It's perfect for my personal site [(trevorlasn.com)](https://www.trevorlasn.com/) because it delivers exactly what I need: **fast load times and seamless content management.**

What really sold me on Astro was its ["islands architecture"](https://docs.astro.build/en/concepts/islands/); I can write most of my site in static HTML and sprinkle in interactivity only where needed. This means my authentication UI can be dynamic while keeping the rest of the site lightweight.

Astro's "islands" of interactivity give me the best of both worlds: the speed of static HTML with the power of React when I actually need it.

### Why Clerk?

Authentication is complex. You need to handle sessions, manage tokens, deal with OAuth providers, implement 2FA, and much more. Clerk handles all of this out of the box, and their free tier is generous - 10,000 monthly active users is more than enough for most projects.

The integration with Astro is surprisingly straightforward. A few lines of code, and you have a complete auth system.

### Getting Started

First, start an Astro project from scratch. If you want to see the code first, you can find it [here](https://github.com/indreklasn/astro-5-clerk-auth)

```bash title="Create a new Astro project"
npm create astro@latest
```

Next, install Clerk.

```bash title="Install Clerk"
npm install @astrojs/node @clerk/astro
```

Finally, add Clerk to your Astro project.

```js ins={2,3,6-8} title="astro.config.mjs"
import { defineConfig } from 'astro/config'
import node from '@astrojs/node'
import clerk from '@clerk/astro'

export default defineConfig({
  integrations: [clerk()],
  adapter: node({ mode: 'standalone' }),
  output: 'server',
})
```

Set your Clerk API keys. You can find these in your Clerk dashboard.

```mdx title=".env"
PUBLIC_CLERK_PUBLISHABLE_KEY=****************************************
CLERK_SECRET_KEY=****************************************
```

Middleware is required to protect your routes. Add the following to your `middleware.ts` file.

```js title="src/middleware.ts"
import { clerkMiddleware, createRouteMatcher } from "@clerk/astro/server";

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', ''])

export const onRequest = clerkMiddleware((auth, context) => {
  const { redirectToSignIn, userId } = auth()

  if (!userId && isProtectedRoute(context.request)) {

    return redirectToSignIn()
  }
})
```

You can customize the routes Clerk protects by modifying the `createRouteMatcher` array. For this example, Clerk will protect the `/dashboard` route.

That's all that's needed to setup the functionality. Next, let's add the UI components.

Clerk provides `SignedOut`, `SignedIn`, `SignInButton` and `UserButton` components. These components make it easy to build a custom authentication UI.

```jsx title="src/components/Layout.astro"
---
import { SignedIn, SignedOut, UserButton, SignInButton } from "@clerk/astro/components";
---
<nav>
  <SignedOut>
    <SignInButton mode="modal" />
  </SignedOut>
  <SignedIn>
    <UserButton />
  </SignedIn>
</nav>
```

* [SignedIn](https://clerk.com/docs/components/control/signed-in): Children of this component can only be seen while signed in.
* [SignedOut](https://clerk.com/docs/components/control/signed-out): Children of this component can only be seen while signed out.
* [UserButton](https://clerk.com/docs/components/user/user-button): Shows the signed-in user's avatar. Selecting it opens a dropdown menu with account management options.
* [SignInButton](https://clerk.com/docs/components/unstyled/sign-in-button): An unstyled component that links to the sign-in page.

Start by creating a route that will be accessible to all users.

```jsx title="src/pages/index.astro"
---
import Layout from '../components/Layout.astro'
---

<Layout title="Astro 5 + Clerk Demo">
  <h1 class="text-2xl font-bold text-white">Sign in to try it out</h1>
</Layout>
```

Next, let's create a protected route. This route will only be accessible to signed-in users. Remember, we protected the `/dashboard` route in the `middleware.ts` file.

```jsx title="src/pages/dashboard.astro"
---
import Layout from '../components/Layout.astro'
---

<Layout title="Astro 5 + Clerk">
  <h1>Dashboard</h1>
  <p>
    Protected route. Only logged in users can see this page.
  </p>
</Layout> 
```

Finally, we can test our setup. Run the following command to start the Astro server.

```bash title="Start the Astro server"
npm run dev
┃ Local    http://localhost:4321/
┃ Network  use --host to expose

17:36:43 watching for file changes...
```

* `'/'` should display the sign-in button.

![Home view](https://res.cloudinary.com/dcxnnco0b/image/upload/w_auto,dpr_auto,f_auto,q_auto/v1734535242/Screenshot_2024-12-18_at_17.18.44_okv9uw.webp)

Clicking the sign-in button should open the Clerk modal.

![Clerk signup modal](https://res.cloudinary.com/dcxnnco0b/image/upload/w_auto,dpr_auto,f_auto,q_auto/v1734535297/Screenshot_2024-12-18_at_17.18.54_uvvjci.webp)

After signing in, you should see the signed in view. The sign-in button should be replaced with the user profile image.

![Signed in home view](https://res.cloudinary.com/dcxnnco0b/image/upload/w_auto,dpr_auto,f_auto,q_auto/v1734535382/Screenshot_2024-12-18_at_17.19.21_j12gsf.webp)

* If everything went smoothly, the `'/dashboard'` route should be accessible only to signed-in users. Otherwise, you'll be redirected to the sign-in page.

![Dashboard view](https://res.cloudinary.com/dcxnnco0b/image/upload/w_auto,dpr_auto,f_auto,q_auto/v1734535448/Screenshot_2024-12-18_at_17.19.30_v3iehj.png)

When we head to the Clerk dashboard, we can see the user we just created.

![Clerk dashboard](https://res.cloudinary.com/dcxnnco0b/image/upload/w_auto,dpr_auto,f_auto,q_auto/v1734535578/Screenshot_2024-12-18_at_17.25.46_jb0kzl.png)

That's it! You now have a fully functional authentication system in your Astro project. You can customize the UI, add 2FA, and much more. [Clerk's documentation](https://clerk.com/docs) is excellent, so you'll have no trouble getting started.

- See full code here: [https://github.com/indreklasn/astro-5-clerk-auth](https://github.com/indreklasn/astro-5-clerk-auth) *(make sure you add the `.env` file with your Clerk API keys)*
