Building Your Ultimate Next.js Boilerplate
Introduction
As developers, we often find ourselves repeating the same setup processes for new projects. Authentication, database connections, payment integrations, and styling – these are the building blocks of most modern web applications. But what if you could skip this repetitive setup and jump straight into building your app's unique features?
In this blog post, we'll explore how to create a powerful boilerplate using Next.js, Tailwind CSS, shadcn/ui, TypeScript, Firebase, PostgreSQL, Prisma, Clerk, and custom authentication. This setup will serve as your launchpad for rapid app development, allowing you to focus on what truly matters – bringing your ideas to life.
Why Build a Boilerplate?
Before we dive into the technical details, let's understand why a custom boilerplate is crucial:
Time-saving: Eliminate repetitive setup tasks
Consistency: Maintain a standardized structure across projects
Best practices: Incorporate industry-standard patterns and tools
Flexibility: Tailor the stack to your preferences and needs
Tech Stack Overview
Our boilerplate will include:
Frontend: Next.js, Tailwind CSS, shadcn/ui
Backend: Next.js API routes
Database: PostgreSQL with Prisma ORM
Authentication: Clerk and custom auth options
Payment: Stripe integration
TypeScript: For type safety and better developer experience
Folder Structure
Here's an example folder structure for our boilerplate:
my-nextjs-boilerplate/
├── src/
│ ├── app/
│ │ ├── api/
│ │ │ ├── auth/
│ │ │ ├── payments/
│ │ │ └── ...
│ │ ├── (auth)/
│ │ │ ├── login/
│ │ │ ├── register/
│ │ │ └── ...
│ │ ├── dashboard/
│ │ └── ...
│ ├── components/
│ │ ├── ui/
│ │ ├── auth/
│ │ └── ...
│ ├── lib/
│ │ ├── prisma.ts
│ │ ├── stripe.ts
│ │ └── ...
│ ├── styles/
│ │ └── globals.css
│ └── types/
├── prisma/
│ └── schema.prisma
├── public/
├── .env
├── .env.example
├── next.config.js
├── package.json
├── tailwind.config.js
└── tsconfig.json
Step-by-Step Implementation
Let's break down the process of creating this boilerplate:
1. Project Initialization
npx create-next-app@latest my-nextjs-boilerplate
cd my-nextjs-boilerplate
Choose the following options:
TypeScript: Yes
ESLint: Yes
Tailwind CSS: Yes
src/
directory: YesApp Router: Yes
2. Install Additional Dependencies
npm install @prisma/client @clerk/nextjs @stripe/stripe-js @stripe/react-stripe-js zod react-hook-form @hookform/resolvers/zod @tanstack/react-query
npm install -D prisma @types/node @types/react @types/react-dom @types/stripe
3. Set Up Tailwind CSS and shadcn/ui
First, initialize shadcn/ui:
npx shadcn-ui@latest init
Then, add some components:
npx shadcn-ui@latest add button card form input
4. Configure Prisma
Initialize Prisma and create your schema:
npx prisma init
Edit prisma/schema.prisma
:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
5. Set Up Authentication with Clerk
Create src/app/api/auth/[...nextauth]/route.ts
:
import { authMiddleware } from "@clerk/nextjs";
export default authMiddleware({
publicRoutes: ["/", "/api/webhooks(.*)"],
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
6. Implement Stripe Integration
Create src/lib/stripe.ts
:
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2022-11-15',
});
7. Create a Custom Hook for Authentication
Create src/hooks/useAuth.ts
:
import { useUser } from "@clerk/nextjs";
import { useRouter } from "next/navigation";
export function useAuth() {
const { isSignedIn, user, isLoaded } = useUser();
const router = useRouter();
const signOut = () => {
// Implement sign out logic
};
return { isSignedIn, user, isLoaded, signOut };
}
8. Implement Protected Routes
Create src/components/auth/ProtectedRoute.tsx
:
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import { ReactNode } from "react";
export function ProtectedRoute({ children }: { children: ReactNode }) {
const { isSignedIn, isLoaded } = useAuth();
const router = useRouter();
if (!isLoaded) {
return <div>Loading...</div>;
}
if (!isSignedIn) {
router.push("/login");
return null;
}
return <>{children}</>;
}
9. Set Up Environment Variables
Create a .env
file:
DATABASE_URL="postgresql://username:password@localhost:5432/mydb"
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
CLERK_SECRET_KEY=your_clerk_secret_key
STRIPE_SECRET_KEY=your_stripe_secret_key
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key
Conclusion
With this boilerplate, you now have a solid foundation for building modern web applications using Next.js, Tailwind CSS, and a powerful set of tools. This setup allows you to focus on your app's unique features without getting bogged down in repetitive setup tasks.
Remember to customize this boilerplate to fit your specific needs. As you work on projects, continue to refine and expand your boilerplate, adding new components and utilities that you find yourself using frequently.
Happy coding, and may your future projects launch faster than ever before!
Subscribe to my newsletter
Read articles from Mikey directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Mikey
Mikey
Undergrad Student in domain of Web developer at Chandigarh University.