clerk-main

Clerk, Next.js 14 and Drizzle ORM boilerplate

Piotr

Piotr

Founder

8 min read

When developing a web application with Next.js, leveraging robust tools and services can significantly streamline the development. Clerk is a comprehensive authentication solution designed to simplify user management, offering a wide range of authentication methods and features with minimal setup. On the other hand, Drizzle ORM is an emerging object-relational mapping tool that promises a smooth database interaction experience that enables developers to write more intuitive and maintainable database queries. Pairing these with Neon, a PostgreSQL-compatible database that offers scalability and ease of management, sets a strong foundation for building scalable, secure, and efficient web applications.

Authentication with Clerk

As the first step, please visit Clerk and create an account. After you have created an account, you should create a new application and pre-select the authentication service (you will be able to change this later).

Blog image

As the next step, go to your app folder, create a .env.local file, and add the keys provided by Clerk.

Blog image

Step 1 - Install Clerk.js for Next.js

sh
1npm install @clerk/nextjs

Step 2 - Set your environment variables (it should be already done, as when you created the app, you have received the keys).

Step 3 - Add ClerkProvider inside your layout.tsx file.

typescript
1import { ClerkProvider } from '@clerk/nextjs'
2
3import type { Metadata } from 'next'
4import { Inter } from 'next/font/google'
5import './globals.css'
6
7const inter = Inter({ subsets: ['latin'] })
8
9export const metadata: Metadata = {
10  title: 'Create Next App',
11  description: 'Generated by create next app',
12}
13
14export default function RootLayout({
15  children,
16}: Readonly<{
17  children: React.ReactNode,
18}>) {
19  return (
20    <ClerkProvider>
21      <html lang="en">
22        <body className={inter.className}>{children}</body>
23      </html>
24    </ClerkProvider>
25  )
26}

Step 4 - Update your middleware.ts file

Update your middleware file or create one at the root of your project or src/ directory if you’re using a src/ directory structure.

The authMiddleware helper enables authentication and is where you’ll configure your protected routes.

/middleware.ts

Setting “/” as a public route will allow users to access the homepage without being authenticated. You can add more routes to the publicRoutes array as needed.

typescript
1import { authMiddleware } from '@clerk/nextjs'
2
3export default authMiddleware({
4  publicRoutes: ['/'],
5})
6
7export const config = {
8  matcher: ['/((?!.+.[w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
9}

And voila! You have set up the Clerk authentication service within your Next.js app.

In order to test it, you quickly create a new folder News and page.tsx file within it. And now if you would like to access your localhost:3000/news you should be redirected to the Clerk login page.

Blog image

Additional Clerk features (latest update)

ClerkLoading

Let’s add a little spinner for the loading state of the Clerk authentication service.

typescript
1import { ClerkLoading } from '@clerk/nextjs'
2import { Loader } from 'lucide-react'
3
4export default function Home() {
5  return (
6    <main>
7      Hello, we will be testing Clerk latest update and Drizzle ORM.
8      <div>
9        <ClerkLoading>
10          <Loader className="text-muted-foreground h-5 w-5" />
11        </ClerkLoading>
12      </div>
13    </main>
14  )
15}

ClerkLoaded, SignedIn, SignedOut, SignInButton, UserButton

Below is an example of how to use ClerkLoaded, SignedIn, SignedOut, SignInButton, and UserButton components. As the latest developments in Clerk.

typescript
1import {
2  ClerkLoading,
3  ClerkLoaded,
4  SignedIn,
5  SignedOut,
6  UserButton,
7  SignInButton,
8} from '@clerk/nextjs'
9
10import { Loader } from 'lucide-react'
11
12export default function Home() {
13  return (
14    <main>
15      Hello, we will be testing Clerk latest update and Drizzle ORM.
16      <div className="flex flex-col">
17        <ClerkLoading>
18          <Loader className="text-muted-foreground h-5 w-5" />
19        </ClerkLoading>
20
21        <ClerkLoaded>
22          <SignedIn>
23            <UserButton afterSignOutUrl="/" />
24          </SignedIn>
25          <SignedOut>
26            <SignInButton
27              mode="modal"
28              afterSignInUrl="/News"
29              afterSignUpUrl="/News"
30            >
31              <button className="w-fit rounded-lg bg-blue-500 p-4 text-white">
32                Sign In
33              </button>
34            </SignInButton>
35          </SignedOut>
36        </ClerkLoaded>
37      </div>
38    </main>
39  )
40}


Blog image

Blog image

Here is the guide for further developments


Time for Drizzle ORM with Neon

Neon describes itself as “The fully managed serverless Postgres with a generous free tier. We separate storage and compute to offer autoscaling, branching, and bottomless storage.”

When you create an account, you will be able to create a new database and get the connection string that looks like this:

sh
1postgresql://neondb_owner:************@ep-calm-......

Add the connection string to your .env.local file.

javascript
1DATABASE_URL=postgresql://neondb_owner:************@ep-calm-......

This is pretty much it for Neon setup. Now let’s move to the Drizzle ORM setup.


Drizzle ORM setup

Head to Drizzle ORM and follow the steps.


Step 1 - Install Drizzle ORM

sh
1npm i drizzle-orm @neondatabase/serverless
2npm i -D drizzle-kit
3

Step 2 - Create a new folder named database in your root directory and create a new file drizzle.ts

typescript
1import { neon } from '@neondatabase/serverless'
2import { drizzle } from 'drizzle-orm/neon-http'
3
4import * as schema from './schema'
5
6const sql = neon(process.env.DATABASE_URL!)
7
8const db = drizzle(sql, { schema })
9
10export default db
11

Step 3 - Create the schema within the database folder.

typescript
1import { pgTable, serial, text } from 'drizzle-orm/pg-core'
2
3export const courses = pgTable('courses', {
4  id: serial('id').primaryKey(),
5  title: text('title').notNull(),
6  imageSrc: text('image_src').notNull(),
7})

Step 4 - In the root of your app, please create drizzle.config.ts file. Also let’s install the dotenv package.

sh
1npm i dotenv

typescript
1import 'dotenv/config'
2import type { Config } from 'drizzle-kit'
3
4export default {
5  schema: './database/schema.ts',
6  out: './drizzle',
7  driver: 'pg',
8  dbCredentials: {
9    connectionString: process.env.DATABASE_URL!,
10  },
11} satisfies Config

Step 5 (optional) - Add the following script to your package.json file.


typescript
1"scripts": {
2    "db:studio": "npx drizzle-kit studio",
3    "db:push": "npx drizzle-kit push:pg",
4}
5

Step 6 — Run the following command to create the database schema.

sh
1npm run db:push

and voila! You have set up the Drizzle ORM with Neon. You can now start creating your models and queries also go and check the studio.

sh
1npm run db:studio

you may need to install pg package for this:

sh
1npm i -D pg

Happy coding :)

Piotr

Fortune 500 fintech expertise for mid-market companies. We deliver enterprise-grade solutions with strategic thinking and technical excellence—without the corporate overhead.

Our Family Members

WebInt PaymentsThe Fine Stack

© 2026 WebInt Studio. All rights reserved.