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

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:

  

#### npm

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

#### bun

```bash
bunx --bun 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:

  

#### npm

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

#### pnpm

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

#### yarn

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

#### bun

```bash
bun add @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:

  

#### npm

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

#### pnpm

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

#### yarn

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

#### bun

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

  

#### npm

```bash
npm install @prisma/client @prisma/adapter-pg dotenv pg
```

#### pnpm

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

#### yarn

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

#### bun

```bash
bun add @prisma/client @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](/orm/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### npm

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

#### bun

```bash
bunx --bun 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:

  

#### npm

```bash
npx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### bun

```bash
bunx --bun 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:
> 
> 
>   
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 
>   #### pnpm

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

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 

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

  

#### npm

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

#### pnpm

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

#### yarn

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

#### bun

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

  

#### npm

```bash
npx prisma generate
```

#### pnpm

```bash
pnpm dlx prisma generate
```

#### yarn

```bash
yarn dlx prisma generate
```

#### bun

```bash
bunx --bun 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:

  

#### npm

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

#### pnpm

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

#### yarn

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

#### bun

```bash
bun add --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.

  

#### npm

```bash
npx prisma studio
```

#### pnpm

```bash
pnpm dlx prisma studio
```

#### yarn

```bash
yarn dlx prisma studio
```

#### bun

```bash
bunx --bun 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've successfully built a Next.js application with Clerk authentication and Prisma, creating a foundation for a secure and scalable full-stack application that handles user management and data persistence with ease.

Below are some next steps to explore, as well as some more resources to help you get started expanding your project.

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](/orm)
* [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