# Clerk (with Next.js) (/docs/guides/authentication/clerk/nextjs)

> 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 a Next.js app with Clerk Auth

Location: Guides > Authentication > Clerk > Clerk (with Next.js)

## Introduction [#introduction]

[Clerk](https://clerk.com/) is a drop-in auth provider that handles sign-up, sign-in, user management, and webhooks so you don't have to.

In this guide you'll wire Clerk into a brand-new [Next.js](https://nextjs.org/) app, persist users in a [Prisma Postgres](https://prisma.io/postgres) database, and expose a tiny posts API. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/clerk-nextjs).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* [Clerk account](https://clerk.com)
* [ngrok account](https://ngrok.com)

## 1. Set up your project [#1-set-up-your-project]

Create the app:

  

#### bun

```bash
bunx create-next-app@latest clerk-nextjs-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest clerk-nextjs-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest clerk-nextjs-prisma
```

#### npm

```bash
npx create-next-app@latest clerk-nextjs-prisma
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *Would you like to use TypeScript?* `Yes`
> * *Would you like to use ESLint?* `Yes`
> * *Would you like to use Tailwind CSS?* `Yes`
> * *Would you like your code inside a `src/` directory?* `No`
> * *Would you like to use App Router?* (recommended) `Yes`
> * *Would you like to use Turbopack for `next dev`?* `Yes`
> * _Would you like to customize the import alias (`@/_`by default)?\*`No`

Navigate to the project directory:

```bash
cd clerk-nextjs-prisma
```

## 2. Set up Clerk [#2-set-up-clerk]

### 2.1. Create a new Clerk application [#21-create-a-new-clerk-application]

[Sign in](https://dashboard.clerk.com/sign-in) to Clerk and navigate to the home page. From there, press the `Create Application` button to create a new application. Enter a title, select your sign-in options, and click `Create Application`.

> [!NOTE]
> For this guide, the Google, Github, and Email sign in options will be used.

Install the Clerk Next.js SDK:

  

#### bun

```bash
bun add @clerk/nextjs
```

#### pnpm

```bash
pnpm add @clerk/nextjs
```

#### yarn

```bash
yarn add @clerk/nextjs
```

#### npm

```bash
npm install @clerk/nextjs
```

Copy your Clerk keys and paste them into **.env** in the root of your project:

```bash title=".env"
# Clerk # [!code ++]
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key> # [!code ++]
CLERK_SECRET_KEY=<your-secret-key> # [!code ++]
```

### 2.2. Protect routes with Clerk middleware [#22-protect-routes-with-clerk-middleware]

The `clerkMiddleware` helper enables authentication and is where you'll configure your protected routes.

Create a `middleware.ts` file in the root directory of your project:

```tsx title="middleware.ts" showLineNumbers
import { clerkMiddleware } from "@clerk/nextjs/server"; // [!code ++]
// [!code ++]
export default clerkMiddleware(); // [!code ++]
// [!code ++]
export const config = {
  // [!code ++]
  matcher: [
    // [!code ++]
    "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", // [!code ++]
    "/(api|trpc)(.*)", // [!code ++]
  ], // [!code ++]
}; // [!code ++]
```

### 2.3. Add Clerk UI to your layout [#23-add-clerk-ui-to-your-layout]

Next, you'll need to wrap your app in the `ClerkProvider` component to make authentication globally available.

In your `layout.tsx` file, add the `ClerkProvider` component:

```tsx title="app/layout.tsx" showLineNumbers
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ClerkProvider } from "@clerk/nextjs"; // [!code ++]

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      {" "}
      // [!code ++]
      <html lang="en">
        <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
          {children}
        </body>
      </html>
    </ClerkProvider> // [!code ++]
  );
}
```

Create a `Navbar` component which will be used to display the Sign In and Sign Up buttons as well as the User Button once a user is signed in:

```tsx title="app/layout.tsx" showLineNumbers
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import {
  ClerkProvider,
  UserButton, // [!code ++]
  SignInButton, // [!code ++]
  SignUpButton, // [!code ++]
  SignedOut, // [!code ++]
  SignedIn, // [!code ++]
} from "@clerk/nextjs";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
          <Navbar /> // [!code ++]
          {children}
        </body>
      </html>
    </ClerkProvider>
  );
}

const Navbar = () => {
  // [!code ++]
  return (
    // [!code ++]
    <header className="flex justify-end items-center p-4 gap-4 h-16">
      {" "}
      // [!code ++]
      <SignedOut>
        {" "}
        // [!code ++]
        <SignInButton /> // [!code ++]
        <SignUpButton /> // [!code ++]
      </SignedOut>{" "}
      // [!code ++]
      <SignedIn>
        {" "}
        // [!code ++]
        <UserButton /> // [!code ++]
      </SignedIn>{" "}
      // [!code ++]
    </header> // [!code ++]
  ); // [!code ++]
}; // [!code ++]
```

## 3. Install and configure Prisma [#3-install-and-configure-prisma]

### 3.1. Install dependencies [#31-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@7.10.0 tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@7.10.0 tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@7.10.0 tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@7.10.0 tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7.10.0 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7.10.0 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7.10.0 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7.10.0 @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 ../app/generated/prisma
```

#### pnpm

```bash
pnpm dlx prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn dlx prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!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 local `DATABASE_URL` in `.env`

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
```

### 3.2. Define your Prisma Schema [#32-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models:

```prisma title="prisma/schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id      Int     @id @default(autoincrement()) // [!code ++]
  clerkId String  @unique // [!code ++]
  email   String  @unique // [!code ++]
  name    String? // [!code ++]
  posts   Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
  createdAt DateTime @default(now()) // [!code ++]
} // [!code ++]
```

This will create two models: `User` and `Post`, with a one-to-many relationship between them.

Create a `prisma.config.ts` file to configure Prisma:

```typescript title="prisma.config.ts" showLineNumbers
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm dlx prisma migrate dev --name init
```

#### yarn

```bash
yarn dlx prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm dlx prisma generate
```

#### yarn

```bash
yarn dlx prisma generate
```

#### npm

```bash
npx prisma generate
```

> [!WARNING]
> It is recommended that you add `/app/generated/prisma` to your `.gitignore` file.

### 3.3. Create a reusable Prisma Client [#33-create-a-reusable-prisma-client]

In the root directory, create a `lib` directory and a `prisma.ts` file inside it:

```tsx title="lib/prisma.ts" showLineNumbers
import { PrismaClient } from "../app/generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL!, // [!code ++]
}); // [!code ++]
// [!code ++]
const globalForPrisma = global as unknown as {
  // [!code ++]
  prisma: PrismaClient; // [!code ++]
}; // [!code ++]
// [!code ++]
const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; // [!code ++]
// [!code ++]
export default prisma; // [!code ++]
```

## 4. Wire Clerk to the database [#4-wire-clerk-to-the-database]

### 4.1. Create a Clerk webhook endpoint [#41-create-a-clerk-webhook-endpoint]

Create a new API route at `app/api/webhooks/clerk/route.ts`:

Import the necessary dependencies:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks"; // [!code ++]
import { NextRequest } from "next/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
```

Create the `POST` method that Clerk will call and verify the webhook:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  // [!code ++]
  try {
    // [!code ++]
    const evt = await verifyWebhook(req); // [!code ++]
    const { id } = evt.data; // [!code ++]
    const eventType = evt.type; // [!code ++]
    console.log(
      // [!code ++]
      `Received webhook with ID ${id} and event type of ${eventType}`, // [!code ++]
    ); // [!code ++]
  } catch (err) {
    // [!code ++]
    console.error("Error verifying webhook:", err); // [!code ++]
    return new Response("Error verifying webhook", { status: 400 }); // [!code ++]
  } // [!code ++]
} // [!code ++]
```

When a new user is created, they need to be stored in the database.

You'll do that by checking if the event type is `user.created` and then using Prisma's `upsert` method to create a new user if they don't exist:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  try {
    const evt = await verifyWebhook(req);
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      // [!code ++]
      const { id, email_addresses, first_name, last_name } = evt.data; // [!code ++]
      await prisma.user.upsert({
        // [!code ++]
        where: { clerkId: id }, // [!code ++]
        update: {}, // [!code ++]
        create: {
          // [!code ++]
          clerkId: id, // [!code ++]
          email: email_addresses[0].email_address, // [!code ++]
          name: `${first_name} ${last_name}`, // [!code ++]
        }, // [!code ++]
      }); // [!code ++]
    } // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
}
```

Finally, return a response to Clerk to confirm the webhook was received:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  try {
    const evt = await verifyWebhook(req);
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      const { id, email_addresses, first_name, last_name } = evt.data;
      await prisma.user.upsert({
        where: { clerkId: id },
        update: {},
        create: {
          clerkId: id,
          email: email_addresses[0].email_address,
          name: `${first_name} ${last_name}`,
        },
      });
    }

    return new Response("Webhook received", { status: 200 }); // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
}
```

### 4.2. Expose your local app for webhooks [#42-expose-your-local-app-for-webhooks]

You'll need to expose your local app for webhooks with [ngrok](https://ngrok.com/). This will allow Clerk to reach your `/api/webhooks/clerk` route to push events like `user.created`.

Install ngrok and expose your local app:

  

#### bun

```bash
bun add --global ngrok
ngrok http 3000
```

#### pnpm

```bash
pnpm add --global ngrok
ngrok http 3000
```

#### yarn

```bash
yarn global add ngrok
ngrok http 3000
```

#### npm

```bash
npm install --global ngrok
ngrok http 3000
```

Copy the ngrok `Forwarding URL`. This will be used to set the webhook URL in Clerk.

Navigate to the ***Webhooks*** section of your Clerk application located near the bottom of the ***Configure*** tab under ***Developers***.

Click ***Add Endpoint*** and paste the ngrok URL into the ***Endpoint URL*** field and add `/api/webhooks/clerk` to the end of the URL. It should look similar to this:

```text
https://a60b-99-42-62-240.ngrok-free.app/api/webhooks/clerk
```

Copy the ***Signing Secret*** and add it to your `.env` file:

```bash title=".env"
# Prisma
DATABASE_URL=<your-database-url>

# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
CLERK_WEBHOOK_SIGNING_SECRET=<your-signing-secret> # [!code ++]
```

On the home page, press Sign Up and create an account using any of the sign-up options

Open Prisma Studio and you should see a user record.

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm dlx prisma studio
```

#### yarn

```bash
yarn dlx prisma studio
```

#### npm

```bash
npx prisma studio
```

> [!NOTE]
> If you don't see a user record, there are a few things to check:
> 
> * Delete your user from the Users tab in Clerk and try again.
> * Check your ngrok URL and ensure it's correct *(it will change everytime you restart ngrok)*.
> * Check your Clerk webhook is pointing to the correct ngrok URL.
> * Make sure you've added `/api/webhooks/clerk` to the end of the URL.

## 5. Build a posts API [#5-build-a-posts-api]

To create posts under a user, you'll need to create a new API route at `app/api/posts/route.ts`:

Start by importing the necessary dependencies:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
```

Get the `clerkId` of the authenticated user. If there's no user, return a `401` Unauthorized response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  // [!code ++]
  const { userId: clerkId } = await auth(); // [!code ++]
  if (!clerkId) return new Response("Unauthorized", { status: 401 }); // [!code ++]
} // [!code ++]
```

Match the Clerk user to a user in the database. If none is found, return a `404` Not Found response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  const { userId: clerkId } = await auth();
  if (!clerkId) return new Response("Unauthorized", { status: 401 });

  const user = await prisma.user.findUnique({
    // [!code ++]
    where: { clerkId }, // [!code ++]
  }); // [!code ++]
  // [!code ++]
  if (!user) return new Response("User not found", { status: 404 }); // [!code ++]
}
```

Destructure the title and content from the incoming request and create a post. Once done, return a `201` Created response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  const { userId: clerkId } = await auth();
  if (!clerkId) return new Response("Unauthorized", { status: 401 });

  const { title, content } = await req.json(); // [!code ++]

  const user = await prisma.user.findUnique({
    where: { clerkId },
  });

  if (!user) return new Response("User not found", { status: 404 });

  const post = await prisma.post.create({
    // [!code ++]
    data: {
      // [!code ++]
      title, // [!code ++]
      content, // [!code ++]
      authorId: user.id, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]

  return new Response(JSON.stringify(post), { status: 201 }); // [!code ++]
}
```

## 6. Add a Post creation UI [#6-add-a-post-creation-ui]

In `/app`, create a `/components` directory and a `PostInputs.tsx` file inside it:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client"; // [!code ++]

import { useState } from "react"; // [!code ++]

export default function PostInputs() {
  // [!code ++]
  const [title, setTitle] = useState(""); // [!code ++]
  const [content, setContent] = useState(""); // [!code ++]
} // [!code ++]
```

This component uses `"use client"` to ensure the component is rendered on the client. The title and content are stored in their own `useState` hooks.

Create a function that will be called when a form is submitted:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client";

import { useState } from "react";

export default function PostInputs() {
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  async function createPost(e: React.FormEvent) {
    // [!code ++]
    e.preventDefault(); // [!code ++]
    if (!title || !content) return; // [!code ++]
    // [!code ++]
    await fetch("/api/posts", {
      // [!code ++]
      method: "POST", // [!code ++]
      headers: { "Content-Type": "application/json" }, // [!code ++]
      body: JSON.stringify({ title, content }), // [!code ++]
    }); // [!code ++]
    // [!code ++]
    setTitle(""); // [!code ++]
    setContent(""); // [!code ++]
    location.reload(); // [!code ++]
  } // [!code ++]
}
```

You'll be using a form to create a post and call the `POST` route you created earlier:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client";

import { useState } from "react";

export default function PostInputs() {
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  async function createPost(e: React.FormEvent) {
    e.preventDefault();
    if (!title || !content) return;

    await fetch("/api/posts", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title, content }),
    });

    setTitle("");
    setContent("");
    location.reload();
  }

  return (
    // [!code ++]
    <form onSubmit={createPost} className="space-y-2">
      {" "}
      // [!code ++]
      <input // [!code ++]
        type="text" // [!code ++]
        placeholder="Title" // [!code ++]
        value={title} // [!code ++]
        onChange={(e) => setTitle(e.target.value)} // [!code ++]
        className="w-full p-2 border border-zinc-800 rounded" // [!code ++]
      />{" "}
      // [!code ++]
      <textarea // [!code ++]
        placeholder="Content" // [!code ++]
        value={content} // [!code ++]
        onChange={(e) => setContent(e.target.value)} // [!code ++]
        className="w-full p-2 border border-zinc-800 rounded" // [!code ++]
      />{" "}
      // [!code ++]
      <button className="w-full p-2 border border-zinc-800 rounded">
        {" "}
        // [!code ++] Post // [!code ++]
      </button>{" "}
      // [!code ++]
    </form> // [!code ++]
  ); // [!code ++]
}
```

On submit:

* It sends a `POST` request to the `/api/posts` route
* Clears the input fields
* Reloads the page to show the new post

## 7. Set up page.tsx [#7-set-up-pagetsx]

Now, update the `page.tsx` file to fetch posts, show the form, and render the list.

Delete everything within `page.tsx`, leaving only the following:

```tsx title="app/page.tsx" showLineNumbers
export default function Home() {
  return ()
}
```

Import the necessary dependencies:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default function Home() {
  return ()
}
```

To ensure only signed-in users can access the post functionality, update the `Home` component to check for a user:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default async function Home() {
  const user = await currentUser(); // [!code ++]
  if (!user) return <div className="flex justify-center">Sign in to post</div>; // [!code ++]

  return ()
}
```

Once a user is found, fetch that user's posts from the database:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default async function Home() {
  const user = await currentUser();
  if (!user) return <div className="flex justify-center">Sign in to post</div>;

  const posts = await prisma.post.findMany({ // [!code ++]
    where: { author: { clerkId: user.id } }, // [!code ++]
    orderBy: { createdAt: "desc" }, // [!code ++]
  }); // [!code ++]

  return ()
}
```

Finally, render the form and post list:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";
import PostInputs from "@/app/components/PostInputs";

export default async function Home() {
  const user = await currentUser();
  if (!user) return <div className="flex justify-center">Sign in to post</div>;

  const posts = await prisma.post.findMany({
    where: { author: { clerkId: user.id } },
    orderBy: { createdAt: "desc" },
  });

  return (
    <main className="max-w-2xl mx-auto p-4">
      {" "}
      // [!code ++]
      <PostInputs /> // [!code ++]
      <div className="mt-8">
        {" "}
        // [!code ++]
        {posts.map(
          (
            post, // [!code ++]
          ) => (
            <div // [!code ++]
              key={post.id} // [!code ++]
              className="p-4 border border-zinc-800 rounded mt-4"
            >
              {" "}
              // [!code ++]
              <h2 className="font-bold">{post.title}</h2> // [!code ++]
              <p className="mt-2">{post.content}</p> // [!code ++]
            </div> // [!code ++]
          ),
        )}{" "}
        // [!code ++]
      </div>{" "}
      // [!code ++]
    </main> // [!code ++]
  );
}
```

You now have a Next.js application where Clerk handles authentication, new sign-ups are synced to your Prisma Postgres database through the webhook, and signed-in users can create and list their own posts.

## Next Steps [#next-steps]

* Add delete functionality to posts and users.
* Add a search bar to filter posts.
* Deploy to Vercel and set your production webhook URL in Clerk.

### More Info [#more-info]

* [Prisma Docs](https://www.prisma.io/docs/orm/v7)
* [Next.js Docs](https://nextjs.org/docs)
* [Clerk Docs](https://clerk.com/docs)

## Related pages

- [`Clerk (with Astro)`](https://www.prisma.io/docs/guides/authentication/clerk/astro): Learn how to use Prisma ORM in an Astro app with Clerk Auth