Skip to content

Getting Started with Next.js#

Set up a modern Next.js project with TypeScript, Tailwind CSS, and Better Auth.

Create New Project#

# Create app with all recommended options
npx create-next-app@latest my-app \
  --typescript \
  --app \
  --tailwind \
  --eslint \
  --src-dir false \
  --import-alias "@/*"

cd my-app

Installation Options Explained#

  • --typescript - TypeScript support
  • --app - Use App Router (modern)
  • --tailwind - Tailwind CSS for styling
  • --eslint - ESLint for code quality
  • --src-dir false - No src folder (keep app/ at root)
  • --import-alias "@/*" - Import paths like @/components/...

Project Structure#

my-app/
├── app/
│   ├── layout.tsx        # Root layout
│   ├── page.tsx          # Home page (/)
│   └── globals.css       # Global styles
├── components/           # Reusable components
├── lib/                  # Utilities, helpers, auth
├── public/               # Static assets
├── types/                # TypeScript types
├── next.config.js        # Next.js configuration
├── tailwind.config.ts    # Tailwind configuration
├── tsconfig.json         # TypeScript configuration
└── package.json

Install Dependencies#

# Better Auth for authentication
npm install better-auth

# Zod for validation
npm install zod

# React Hook Form (optional, for forms)
npm install react-hook-form @hookform/resolvers

# UI primitives (optional)
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu

# Utilities
npm install clsx tailwind-merge class-variance-authority

Root Layout#

// app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "My App",
  description: "Built with Next.js and Better Auth",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        {children}
      </body>
    </html>
  );
}

Home Page#

// app/page.tsx
export default function Home() {
  return (
    <main className="min-h-screen flex items-center justify-center">
      <div className="text-center">
        <h1 className="text-4xl font-bold mb-4">
          Welcome to Next.js
        </h1>
        <p className="text-gray-600">
          Your app is ready to go!
        </p>
      </div>
    </main>
  );
}

Run Development Server#

npm run dev

Visit http://localhost:3000

Environment Variables#

# .env.local
DATABASE_URL="postgresql://..."
BETTER_AUTH_SECRET="your-secret-key"
BETTER_AUTH_URL="http://localhost:3000"

Never commit .env.local - add to .gitignore

Folder Organization#

Use parentheses to group routes without affecting URLs:

app/
├── (auth)/              # Auth pages (login, signup)
│   ├── login/
│   │   └── page.tsx     → /login
│   └── signup/
│       └── page.tsx     → /signup
├── (protected)/         # Protected routes
│   ├── dashboard/
│   │   └── page.tsx     → /dashboard
│   ├── profile/
│   │   └── page.tsx     → /profile
│   └── layout.tsx       # Layout for protected pages
└── page.tsx             → /

Component Organization#

components/
├── ui/                  # Reusable UI components
│   ├── button.tsx
│   ├── input.tsx
│   └── card.tsx
├── auth/                # Auth-specific components
│   ├── login-form.tsx
│   └── signup-form.tsx
└── shared/              # Shared across app
    ├── navbar.tsx
    └── footer.tsx

Lib Organization#

lib/
├── auth.ts              # Better Auth config
├── db.ts                # Database connection
├── utils.ts             # Utility functions
└── validations.ts       # Zod schemas

TypeScript Configuration#

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [{ "name": "next" }],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Next.js Configuration#

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Allow images from external domains
  images: {
    domains: ['avatars.githubusercontent.com'],
  },
  // Enable strict mode
  reactStrictMode: true,
}

module.exports = nextConfig

Utility Functions#

cn() - Merge Tailwind Classes#

// lib/utils.ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

// Usage
<div className={cn("bg-blue-500", someCondition && "bg-red-500")} />

Import Aliases#

// ✅ With @ alias
import { Button } from "@/components/ui/button";
import { auth } from "@/lib/auth";

// ❌ Without alias
import { Button } from "../../components/ui/button";
import { auth } from "../lib/auth";

Development Scripts#

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }
}
npm run dev     # Start development server
npm run build   # Build for production
npm run start   # Start production server
npm run lint    # Run ESLint

Debugging#

Enable Source Maps#

// next.config.js
const nextConfig = {
  productionBrowserSourceMaps: true,
}

React DevTools#

Install React DevTools browser extension.

Next.js DevTools#

Built-in - accessible at http://localhost:3000 during development.

Gitignore#

# .gitignore
node_modules/
.next/
.env*.local
.vercel
*.log

Best Practices#

  1. Use TypeScript - Type safety prevents bugs
  2. Configure path aliases - Use @/ imports
  3. Organize by feature - Group related files together
  4. Use route groups - (auth), (protected) for organization
  5. Environment variables - Never commit secrets
  6. Enable strict mode - Catch bugs early

Quick Reference#

Command Description
npm run dev Start dev server on port 3000
npm run build Build for production
npm run start Start production server
npx next info Show Next.js version info

Next Steps#