procursorrules.com
RulesGenerateMCP ServersBlog
Sign In

Ready to enhance your cursor experience?

Join our community today and get access to exclusive cursor rules, resources, and connect with other cursor enthusiasts.

Get StartedLearn More
procursorrules.com

The home for Cursor enthusiasts where you can explore and generate rules, browse MCPs, post and follow the latest news, learn, connect, and discover jobs.

GitHubTwitter

Products

  • Cursor Rules
  • MCP Directory
  • Rule Generator

Resources

  • Cursor Documentation
  • Blog
  • Support

Frendlink

  • FluxKontext.biz
  • BG Remove Pro
  • Labubu Style Generator
  • LaunchVault
  • OG Generator
  • Just Simple Tools

Stay Updated

Subscribe to our newsletter to get the latest updates on cursor rules, tutorials, and community news.

By subscribing, you agree to our Terms and Privacy Policy.

  • Featured on findly.tools
  • Startup Benchmarks
  • Acid Tools
  • AIGC 160
  • AI Toolz
  • z-image.win
  • Launch Vault
  • Hunt for Tools
  • SaaS Field
  • SaaS Hub Directory
  • SaaS Roots
© 2026 Pro Cursor Rules. All rights reserved.
Terms of Service
Privacy Policy
About Us
Made withbySkyler Scofield
Next.js + Shadcn/UI + TypeScript + BetterAuth: Complete Cursor Rules Guide | Pro Cursor Rules
Back to blog
Blog / fullstack

Next.js + Shadcn/UI + TypeScript + BetterAuth: Complete Cursor Rules Guide

Next.js + Shadcn/UI + TypeScript + BetterAuth: Complete Cursor Rules Guide
fullstack
betterauth
cursor
fullstack
nextjs
productivity
shadcn
typescript
C
Cursor Rules Pro Team
Expert Development Team
2025-08-31
26 min read

Next.js + Shadcn/UI + TypeScript + BetterAuth: Complete Cursor Rules Guide

The modern web development landscape demands efficiency, type safety, and rapid prototyping capabilities. The combination of Next.js, Shadcn/UI, TypeScript, and BetterAuth represents one of the most powerful and developer-friendly stacks available today. When enhanced with intelligent Cursor Rules, this stack becomes a productivity powerhouse that can accelerate your development workflow by 10x.

Why This Tech Stack Dominates Modern Development

The Perfect Quartet

This technology stack has become the go-to choice for modern web applications, and for good reason:

  • Next.js: The React framework that provides server-side rendering, API routes, and exceptional developer experience
  • Shadcn/UI: A modern component library built on Radix UI and Tailwind CSS, offering beautiful and accessible components
  • TypeScript: Static typing that catches errors early and improves code maintainability
  • BetterAuth: A modern authentication library that simplifies complex auth flows with excellent TypeScript support
Share this article

Related Articles

Cursor AI: The Code Editor That Actually Gets Your Project
cursor-editor

Cursor AI: The Code Editor That Actually Gets Your Project

Discover why Cursor AI goes beyond simple autocomplete to become your intelligent coding partner. Learn how it understands your entire project and transforms your development workflow.

2025-09-013 min read
Getting Started with Cursor: A Practical Setup Guide
cursor-editor

Getting Started with Cursor: A Practical Setup Guide

Learn how to set up Cursor AI editor from scratch. A complete guide covering installation, configuration, extensions, and essential features to get you productive from day one.

2025-09-014 min read

Comments

YU
Markdown supported

Table of Contents

Why This Tech Stack Dominates Modern DevelopmentThe Perfect QuartetWhy Cursor Rules MatterBenefits of Smart Automation✅ Developer Experience AdvantagesEssential Cursor Rules for Next.js1. Next.js App Router Rules2. Server Components and Client ComponentsShadcn/UI Component Rules1. Form Components with Validation

Why Cursor Rules Matter

Without intelligent assistance, working with this stack involves:

  • Import Hell: Managing dozens of import statements across components
  • Component Prop Discovery: Remembering complex prop interfaces for Shadcn components
  • Auth Pattern Repetition: Writing similar authentication logic repeatedly
  • Type Safety Gaps: Missing type definitions that could prevent runtime errors

Benefits of Smart Automation

With proper Cursor Rules, you achieve:

✅ Developer Experience Advantages

  • 🚀 Instant Setup: Automated project scaffolding with best practices
  • 🎯 Smart Imports: Automatic import suggestions for components and utilities
  • 📱 Component Intelligence: Context-aware Shadcn component suggestions
  • 🔐 Auth Patterns: Pre-built authentication flows and middleware
  • 🛡️ Type Safety: Comprehensive TypeScript coverage with minimal effort

Essential Cursor Rules for Next.js

1. Next.js App Router Rules

Next.js Page Component Rules (TypeScript)

{
  "name": "Next.js App Router Page",
  "description": "Generate App Router page components with TypeScript",
  "trigger": "nextpage",
  "expansion": "export default function ${1:PageName}({ params, searchParams }: { params: { ${2:slug}: string }, searchParams: { [key: string]: string | string[] | undefined } }) {\n  return (\n    <div className=\"container mx-auto py-8\">\n      <h1 className=\"text-3xl font-bold\">${3:Page Title}</h1>\n      $0\n    </div>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

Next.js API Route Rules (TypeScript)

{
  "name": "Next.js API Route",
  "description": "Generate typed API route handlers",
  "trigger": "nextapi",
  "expansion": "import { NextRequest, NextResponse } from 'next/server'\n\nexport async function GET(request: NextRequest) {\n  try {\n    $1\n    return NextResponse.json({ success: true })\n  } catch (error) {\n    return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })\n  }\n}\n\nexport async function POST(request: NextRequest) {\n  try {\n    const body = await request.json()\n    $2\n    return NextResponse.json({ success: true })\n  } catch (error) {\n    return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })\n  }\n}",
  "scope": ["typescript"]
}

2. Server Components and Client Components

Server Component Rules (TypeScript)

{
  "name": "Next.js Server Component",
  "description": "Generate async server components with proper typing",
  "trigger": "servercomp",
  "expansion": "interface ${1:Component}Props {\n  ${2:id}: string\n}\n\nexport default async function ${1:Component}({ ${2:id} }: ${1:Component}Props) {\n  // Server-side data fetching\n  const data = await fetch${3:Data}(${2:id})\n  \n  return (\n    <div>\n      {/* Server-rendered content */}\n      $0\n    </div>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

Client Component Rules (TypeScript)

{
  "name": "Next.js Client Component",
  "description": "Generate client components with hooks",
  "trigger": "clientcomp",
  "expansion": "'use client'\n\nimport { useState } from 'react'\n\ninterface ${1:Component}Props {\n  ${2:initialValue}?: string\n}\n\nexport default function ${1:Component}({ ${2:initialValue} }: ${1:Component}Props) {\n  const [${3:state}, set${3:State}] = useState(${2:initialValue} || '')\n  \n  return (\n    <div>\n      {/* Client-side interactive content */}\n      $0\n    </div>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

Shadcn/UI Component Rules

1. Form Components with Validation

Shadcn Form Rules (TypeScript)

{
  "name": "Shadcn Form with Validation",
  "description": "Generate forms with react-hook-form and zod validation",
  "trigger": "shadform",
  "expansion": "import { zodResolver } from '@hookform/resolvers/zod'\nimport { useForm } from 'react-hook-form'\nimport * as z from 'zod'\nimport { Button } from '@/components/ui/button'\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'\nimport { Input } from '@/components/ui/input'\n\nconst formSchema = z.object({\n  ${1:fieldName}: z.string().min(${2:2}, {\n    message: '${3:Field must be at least 2 characters.}',\n  }),\n})\n\nexport function ${4:FormName}() {\n  const form = useForm<z.infer<typeof formSchema>>({\n    resolver: zodResolver(formSchema),\n    defaultValues: {\n      ${1:fieldName}: '',\n    },\n  })\n\n  function onSubmit(values: z.infer<typeof formSchema>) {\n    console.log(values)\n  }\n\n  return (\n    <Form {...form}>\n      <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n        <FormField\n          control={form.control}\n          name=\"${1:fieldName}\"\n          render={({ field }) => (\n            <FormItem>\n              <FormLabel>${5:Field Label}</FormLabel>\n              <FormControl>\n                <Input placeholder=\"${6:Enter value}\" {...field} />\n              </FormControl>\n              <FormMessage />\n            </FormItem>\n          )}\n        />\n        <Button type=\"submit\">Submit</Button>\n      </form>\n    </Form>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

2. Data Table Components

Shadcn Data Table Rules (TypeScript)

{
  "name": "Shadcn Data Table",
  "description": "Generate data tables with sorting and filtering",
  "trigger": "shadtable",
  "expansion": "import {\n  ColumnDef,\n  flexRender,\n  getCoreRowModel,\n  useReactTable,\n} from '@tanstack/react-table'\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '@/components/ui/table'\n\ninterface ${1:DataType} {\n  id: string\n  ${2:name}: string\n  ${3:email}: string\n}\n\ninterface DataTableProps {\n  columns: ColumnDef<${1:DataType}>[]\n  data: ${1:DataType}[]\n}\n\nexport function DataTable({ columns, data }: DataTableProps) {\n  const table = useReactTable({\n    data,\n    columns,\n    getCoreRowModel: getCoreRowModel(),\n  })\n\n  return (\n    <div className=\"rounded-md border\">\n      <Table>\n        <TableHeader>\n          {table.getHeaderGroups().map((headerGroup) => (\n            <TableRow key={headerGroup.id}>\n              {headerGroup.headers.map((header) => {\n                return (\n                  <TableHead key={header.id}>\n                    {header.isPlaceholder\n                      ? null\n                      : flexRender(\n                          header.column.columnDef.header,\n                          header.getContext()\n                        )}\n                  </TableHead>\n                )\n              })}\n            </TableRow>\n          ))}\n        </TableHeader>\n        <TableBody>\n          {table.getRowModel().rows?.length ? (\n            table.getRowModel().rows.map((row) => (\n              <TableRow\n                key={row.id}\n                data-state={row.getIsSelected() && 'selected'}\n              >\n                {row.getVisibleCells().map((cell) => (\n                  <TableCell key={cell.id}>\n                    {flexRender(cell.column.columnDef.cell, cell.getContext())}\n                  </TableCell>\n                ))}\n              </TableRow>\n            ))\n          ) : (\n            <TableRow>\n              <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n                No results.\n              </TableCell>\n            </TableRow>\n          )}\n        </TableBody>\n      </Table>\n    </div>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

3. Dialog and Modal Patterns

Shadcn Dialog Rules (TypeScript)

{
  "name": "Shadcn Dialog Component",
  "description": "Generate modal dialogs with proper state management",
  "trigger": "shaddialog",
  "expansion": "import {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from '@/components/ui/dialog'\nimport { Button } from '@/components/ui/button'\n\ninterface ${1:Dialog}Props {\n  open?: boolean\n  onOpenChange?: (open: boolean) => void\n  ${2:title}: string\n  ${3:description}?: string\n  children: React.ReactNode\n}\n\nexport function ${1:Dialog}({\n  open,\n  onOpenChange,\n  ${2:title},\n  ${3:description},\n  children,\n}: ${1:Dialog}Props) {\n  return (\n    <Dialog open={open} onOpenChange={onOpenChange}>\n      <DialogTrigger asChild>\n        <Button variant=\"outline\">${4:Open Dialog}</Button>\n      </DialogTrigger>\n      <DialogContent className=\"sm:max-w-[425px]\">\n        <DialogHeader>\n          <DialogTitle>{${2:title}}</DialogTitle>\n          {${3:description} && (\n            <DialogDescription>\n              {${3:description}}\n            </DialogDescription>\n          )}\n        </DialogHeader>\n        <div className=\"grid gap-4 py-4\">\n          {children}\n        </div>\n        <DialogFooter>\n          <Button type=\"submit\">${5:Save changes}</Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

TypeScript Integration Rules

1. Type Definitions and Interfaces

TypeScript Interface Rules

{
  "name": "TypeScript Interface",
  "description": "Generate comprehensive interfaces with optional properties",
  "trigger": "tsinterface",
  "expansion": "interface ${1:InterfaceName} {\n  id: string\n  ${2:name}: string\n  ${3:email}?: string\n  ${4:createdAt}: Date\n  ${5:updatedAt}: Date\n}",
  "scope": ["typescript", "tsx"]
}

API Response Types Rules

{
  "name": "API Response Types",
  "description": "Generate typed API response interfaces",
  "trigger": "apitype",
  "expansion": "interface ${1:Resource} {\n  id: string\n  ${2:attributes}: string\n  createdAt: string\n  updatedAt: string\n}\n\ninterface ${1:Resource}Response {\n  data: ${1:Resource}\n  message?: string\n}\n\ninterface ${1:Resource}ListResponse {\n  data: ${1:Resource}[]\n  pagination: {\n    page: number\n    limit: number\n    total: number\n    totalPages: number\n  }\n  message?: string\n}\n\ninterface ApiError {\n  error: string\n  message: string\n  statusCode: number\n}",
  "scope": ["typescript", "tsx"]
}

2. Custom Hooks with TypeScript

Custom Hook Rules (TypeScript)

{
  "name": "Custom React Hook",
  "description": "Generate typed custom hooks with proper return types",
  "trigger": "tshook",
  "expansion": "import { useState, useEffect } from 'react'\n\ninterface Use${1:Hook}Options {\n  ${2:option}?: string\n}\n\ninterface Use${1:Hook}Return {\n  ${3:data}: ${4:string} | null\n  ${5:loading}: boolean\n  ${6:error}: string | null\n  ${7:refetch}: () => void\n}\n\nexport function use${1:Hook}(options: Use${1:Hook}Options = {}): Use${1:Hook}Return {\n  const [${3:data}, set${3:Data}] = useState<${4:string} | null>(null)\n  const [${5:loading}, set${5:Loading}] = useState(false)\n  const [${6:error}, set${6:Error}] = useState<string | null>(null)\n\n  const fetch${3:Data} = async () => {\n    set${5:Loading}(true)\n    set${6:Error}(null)\n    \n    try {\n      // Implement fetch logic\n      const result = await fetch${8:API}(options.${2:option})\n      set${3:Data}(result)\n    } catch (err) {\n      set${6:Error}(err instanceof Error ? err.message : 'An error occurred')\n    } finally {\n      set${5:Loading}(false)\n    }\n  }\n\n  useEffect(() => {\n    fetch${3:Data}()\n  }, [options.${2:option}])\n\n  return {\n    ${3:data},\n    ${5:loading},\n    ${6:error},\n    ${7:refetch}: fetch${3:Data},\n  }\n}",
  "scope": ["typescript", "tsx"]
}

BetterAuth Integration Rules

1. Authentication Setup

BetterAuth Configuration Rules

{
  "name": "BetterAuth Configuration",
  "description": "Generate BetterAuth setup with providers",
  "trigger": "betterauth",
  "expansion": "import { betterAuth } from 'better-auth'\nimport { prismaAdapter } from 'better-auth/adapters/prisma'\nimport { prisma } from '@/lib/prisma'\n\nexport const auth = betterAuth({\n  database: prismaAdapter(prisma, {\n    provider: 'postgresql', // or 'mysql', 'sqlite'\n  }),\n  socialProviders: {\n    github: {\n      clientId: process.env.GITHUB_CLIENT_ID as string,\n      clientSecret: process.env.GITHUB_CLIENT_SECRET as string,\n    },\n    google: {\n      clientId: process.env.GOOGLE_CLIENT_ID as string,\n      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,\n    },\n  },\n  user: {\n    additionalFields: {\n      ${1:role}: {\n        type: 'string',\n        required: false,\n      },\n    },\n  },\n  session: {\n    expiresIn: 60 * 60 * 24 * 7, // 7 days\n    updateAge: 60 * 60 * 24, // 1 day\n  },\n})",
  "scope": ["typescript"]
}

Auth Client Hook Rules

{
  "name": "BetterAuth Client Hook",
  "description": "Generate client-side auth hooks",
  "trigger": "authclient",
  "expansion": "import { createAuthClient } from 'better-auth/react'\n\nexport const authClient = createAuthClient({\n  baseURL: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',\n})\n\nexport const {\n  signIn,\n  signOut,\n  signUp,\n  useSession,\n} = authClient",
  "scope": ["typescript"]
}

2. Authentication Components

Protected Route Component Rules

{
  "name": "Protected Route Component",
  "description": "Generate protected route wrapper with auth checks",
  "trigger": "protectedroute",
  "expansion": "'use client'\n\nimport { useSession } from '@/lib/auth-client'\nimport { useRouter } from 'next/navigation'\nimport { useEffect } from 'react'\nimport { Loader2 } from 'lucide-react'\n\ninterface ProtectedRouteProps {\n  children: React.ReactNode\n  ${1:requiredRole}?: string\n}\n\nexport function ProtectedRoute({ children, ${1:requiredRole} }: ProtectedRouteProps) {\n  const { data: session, isPending } = useSession()\n  const router = useRouter()\n\n  useEffect(() => {\n    if (!isPending && !session) {\n      router.push('/auth/signin')\n      return\n    }\n\n    if (${1:requiredRole} && session?.user?.${2:role} !== ${1:requiredRole}) {\n      router.push('/unauthorized')\n      return\n    }\n  }, [session, isPending, ${1:requiredRole}, router])\n\n  if (isPending) {\n    return (\n      <div className=\"flex items-center justify-center min-h-screen\">\n        <Loader2 className=\"h-8 w-8 animate-spin\" />\n      </div>\n    )\n  }\n\n  if (!session || (${1:requiredRole} && session.user?.${2:role} !== ${1:requiredRole})) {\n    return null\n  }\n\n  return <>{children}</>\n}",
  "scope": ["typescript", "tsx"]
}

Sign In Form Rules

{
  "name": "BetterAuth Sign In Form",
  "description": "Generate sign-in form with social providers",
  "trigger": "signinform",
  "expansion": "'use client'\n\nimport { useState } from 'react'\nimport { signIn } from '@/lib/auth-client'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Github } from 'lucide-react'\n\nexport function SignInForm() {\n  const [email, setEmail] = useState('')\n  const [password, setPassword] = useState('')\n  const [isLoading, setIsLoading] = useState(false)\n\n  const handleEmailSignIn = async (e: React.FormEvent) => {\n    e.preventDefault()\n    setIsLoading(true)\n    \n    try {\n      await signIn.email({\n        email,\n        password,\n      })\n    } catch (error) {\n      console.error('Sign in error:', error)\n    } finally {\n      setIsLoading(false)\n    }\n  }\n\n  const handleSocialSignIn = async (provider: '${1:github}' | '${2:google}') => {\n    try {\n      await signIn.social({\n        provider,\n        callbackURL: '/dashboard',\n      })\n    } catch (error) {\n      console.error('Social sign in error:', error)\n    }\n  }\n\n  return (\n    <Card className=\"w-full max-w-md mx-auto\">\n      <CardHeader>\n        <CardTitle>Sign In</CardTitle>\n        <CardDescription>\n          Enter your email below to sign in to your account\n        </CardDescription>\n      </CardHeader>\n      <CardContent className=\"space-y-4\">\n        <form onSubmit={handleEmailSignIn} className=\"space-y-4\">\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"email\">Email</Label>\n            <Input\n              id=\"email\"\n              type=\"email\"\n              placeholder=\"m@example.com\"\n              value={email}\n              onChange={(e) => setEmail(e.target.value)}\n              required\n            />\n          </div>\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"password\">Password</Label>\n            <Input\n              id=\"password\"\n              type=\"password\"\n              value={password}\n              onChange={(e) => setPassword(e.target.value)}\n              required\n            />\n          </div>\n          <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n            {isLoading ? 'Signing in...' : 'Sign In'}\n          </Button>\n        </form>\n        \n        <div className=\"relative\">\n          <div className=\"absolute inset-0 flex items-center\">\n            <span className=\"w-full border-t\" />\n          </div>\n          <div className=\"relative flex justify-center text-xs uppercase\">\n            <span className=\"bg-background px-2 text-muted-foreground\">\n              Or continue with\n            </span>\n          </div>\n        </div>\n        \n        <div className=\"grid grid-cols-2 gap-4\">\n          <Button\n            variant=\"outline\"\n            onClick={() => handleSocialSignIn('${1:github}')}\n          >\n            <Github className=\"mr-2 h-4 w-4\" />\n            GitHub\n          </Button>\n          <Button\n            variant=\"outline\"\n            onClick={() => handleSocialSignIn('${2:google}')}\n          >\n            <svg className=\"mr-2 h-4 w-4\" viewBox=\"0 0 24 24\">\n              <path\n                d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n                fill=\"#4285F4\"\n              />\n              <path\n                d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n                fill=\"#34A853\"\n              />\n              <path\n                d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n                fill=\"#FBBC05\"\n              />\n              <path\n                d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n                fill=\"#EA4335\"\n              />\n            </svg>\n            Google\n          </Button>\n        </div>\n      </CardContent>\n    </Card>\n  )\n}",
  "scope": ["typescript", "tsx"]
}

Real-World Application Examples

Example 1: E-commerce Product Dashboard

Let's build a comprehensive product dashboard using our tech stack with Cursor Rules assistance:

Product Dashboard Component (TSX)

'use client'

import { useState, useEffect } from 'react'
import { useSession } from '@/lib/auth-client'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Plus, Search, Filter } from 'lucide-react'

interface Product {
  id: string
  name: string
  price: number
  category: string
  status: 'active' | 'inactive' | 'draft'
  createdAt: string
}

export default function ProductDashboard() {
  const { data: session } = useSession()
  const [products, setProducts] = useState<Product[]>([])
  const [searchTerm, setSearchTerm] = useState('')
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    fetchProducts()
  }, [])

  const fetchProducts = async () => {
    try {
      const response = await fetch('/api/products')
      const data = await response.json()
      setProducts(data.products)
    } catch (error) {
      console.error('Failed to fetch products:', error)
    } finally {
      setLoading(false)
    }
  }

  const filteredProducts = products.filter(product =>
    product.name.toLowerCase().includes(searchTerm.toLowerCase())
  )

  if (loading) {
    return <div className="flex items-center justify-center p-8">Loading...</div>
  }

  return (
    <div className="container mx-auto py-8">
      <div className="flex justify-between items-center mb-8">
        <div>
          <h1 className="text-3xl font-bold">Products</h1>
          <p className="text-muted-foreground">Manage your product inventory</p>
        </div>
        <Button>
          <Plus className="mr-2 h-4 w-4" />
          Add Product
        </Button>
      </div>

      <div className="flex gap-4 mb-6">
        <div className="relative flex-1 max-w-sm">
          <Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
          <Input
            placeholder="Search products..."
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
            className="pl-10"
          />
        </div>
        <Button variant="outline">
          <Filter className="mr-2 h-4 w-4" />
          Filter
        </Button>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {filteredProducts.map((product) => (
          <Card key={product.id} className="hover:shadow-lg transition-shadow">
            <CardHeader>
              <div className="flex justify-between items-start">
                <CardTitle className="line-clamp-1">{product.name}</CardTitle>
                <Badge variant={product.status === 'active' ? 'default' : 'secondary'}>
                  {product.status}
                </Badge>
              </div>
              <CardDescription>${product.price.toFixed(2)}</CardDescription>
            </CardHeader>
            <CardContent>
              <div className="flex justify-between items-center">
                <span className="text-sm text-muted-foreground">{product.category}</span>
                <Button variant="outline" size="sm">
                  Edit
                </Button>
              </div>
            </CardContent>
          </Card>
        ))}
      </div>

      {filteredProducts.length === 0 && (
        <div className="text-center py-12">
          <p className="text-muted-foreground">No products found</p>
        </div>
      )}
    </div>
  )
}

Cursor Rules Assistance Process

  1. Type nextpage → Generated the page component structure
  2. Type tshook → Created the custom hook for data fetching
  3. Type shadtable → Added the data table functionality
  4. Type protectedroute → Wrapped with authentication

Example 2: User Profile Management

User Profile Form Component (TSX)

'use client'

import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import * as z from 'zod'
import { useSession } from '@/lib/auth-client'
import { Button } from '@/components/ui/button'
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { toast } from '@/components/ui/use-toast'

const profileFormSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  bio: z.string().max(500, 'Bio must be less than 500 characters').optional(),
  website: z.string().url('Invalid URL').optional().or(z.literal('')),
})

type ProfileFormValues = z.infer<typeof profileFormSchema>

export default function UserProfile() {
  const { data: session } = useSession()
  
  const form = useForm<ProfileFormValues>({
    resolver: zodResolver(profileFormSchema),
    defaultValues: {
      name: session?.user?.name || '',
      email: session?.user?.email || '',
      bio: session?.user?.bio || '',
      website: session?.user?.website || '',
    },
  })

  async function onSubmit(data: ProfileFormValues) {
    try {
      const response = await fetch('/api/user/profile', {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      })

      if (response.ok) {
        toast({
          title: 'Profile updated',
          description: 'Your profile has been updated successfully.',
        })
      } else {
        throw new Error('Failed to update profile')
      }
    } catch (error) {
      toast({
        title: 'Error',
        description: 'Failed to update profile. Please try again.',
        variant: 'destructive',
      })
    }
  }

  return (
    <div className="container mx-auto py-8 max-w-2xl">
      <Card>
        <CardHeader>
          <CardTitle>Profile Settings</CardTitle>
          <CardDescription>
            Update your profile information and preferences.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-6">
          <div className="flex items-center space-x-4">
            <Avatar className="h-20 w-20">
              <AvatarImage src={session?.user?.image} alt={session?.user?.name} />
              <AvatarFallback>
                {session?.user?.name?.charAt(0)?.toUpperCase()}
              </AvatarFallback>
            </Avatar>
            <Button variant="outline">Change Avatar</Button>
          </div>

          <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
              <FormField
                control={form.control}
                name="name"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Full Name</FormLabel>
                    <FormControl>
                      <Input placeholder="Enter your full name" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <FormField
                control={form.control}
                name="email"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Email</FormLabel>
                    <FormControl>
                      <Input placeholder="Enter your email" type="email" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <FormField
                control={form.control}
                name="bio"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Bio</FormLabel>
                    <FormControl>
                      <Textarea
                        placeholder="Tell us about yourself"
                        className="resize-none"
                        {...field}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <FormField
                control={form.control}
                name="website"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Website</FormLabel>
                    <FormControl>
                      <Input placeholder="https://your-website.com" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <Button type="submit" className="w-full">
                Update Profile
              </Button>
            </form>
          </Form>
        </CardContent>
      </Card>
    </div>
  )
}

Advanced Integration Patterns

1. Middleware and Route Protection

Authentication Middleware Rules

{
  "name": "Next.js Auth Middleware",
  "description": "Generate middleware for route protection",
  "trigger": "authmiddleware",
  "expansion": "import { NextRequest, NextResponse } from 'next/server'\nimport { auth } from '@/lib/auth'\n\nexport async function middleware(request: NextRequest) {\n  const { pathname } = request.nextUrl\n  \n  // Public routes that don't require authentication\n  const publicRoutes = ['/auth/signin', '/auth/signup', '/api/auth', '/']\n  \n  if (publicRoutes.some(route => pathname.startsWith(route))) {\n    return NextResponse.next()\n  }\n  \n  // Check for authentication\n  const session = await auth.api.getSession({\n    headers: request.headers,\n  })\n  \n  if (!session) {\n    const signInUrl = new URL('/auth/signin', request.url)\n    signInUrl.searchParams.set('callbackUrl', pathname)\n    return NextResponse.redirect(signInUrl)\n  }\n  \n  // Role-based route protection\n  const adminRoutes = ['/admin']\n  if (adminRoutes.some(route => pathname.startsWith(route))) {\n    if (session.user.role !== 'admin') {\n      return NextResponse.redirect(new URL('/unauthorized', request.url))\n    }\n  }\n  \n  return NextResponse.next()\n}\n\nexport const config = {\n  matcher: [\n    '/((?!api|_next/static|_next/image|favicon.ico).*)',\n  ],\n}",
  "scope": ["typescript"]
}

2. Database Integration with Prisma

Prisma Schema Rules

{
  "name": "Prisma Schema Models",
  "description": "Generate Prisma models for BetterAuth integration",
  "trigger": "prismaauth",
  "expansion": "model User {\n  id            String          @id @default(cuid())\n  name          String?\n  email         String          @unique\n  emailVerified DateTime?\n  image         String?\n  role          Role            @default(USER)\n  accounts      Account[]\n  sessions      Session[]\n  posts         Post[]\n  createdAt     DateTime        @default(now())\n  updatedAt     DateTime        @updatedAt\n\n  @@map(\"users\")\n}\n\nmodel Account {\n  id                String  @id @default(cuid())\n  userId            String\n  type              String\n  provider          String\n  providerAccountId String\n  refresh_token     String? @db.Text\n  access_token      String? @db.Text\n  expires_at        Int?\n  token_type        String?\n  scope             String?\n  id_token          String? @db.Text\n  session_state     String?\n\n  user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n  @@unique([provider, providerAccountId])\n  @@map(\"accounts\")\n}\n\nmodel Session {\n  id           String   @id @default(cuid())\n  sessionToken String   @unique\n  userId       String\n  expires      DateTime\n  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n  @@map(\"sessions\")\n}\n\nmodel VerificationToken {\n  identifier String\n  token      String   @unique\n  expires    DateTime\n\n  @@unique([identifier, token])\n  @@map(\"verificationtokens\")\n}\n\nenum Role {\n  USER\n  ADMIN\n  MODERATOR\n}",
  "scope": ["prisma"]
}

3. API Route Patterns

CRUD API Routes Rules

{
  "name": "CRUD API Routes",
  "description": "Generate complete CRUD operations with auth",
  "trigger": "crudapi",
  "expansion": "import { NextRequest, NextResponse } from 'next/server'\nimport { auth } from '@/lib/auth'\nimport { prisma } from '@/lib/prisma'\nimport { z } from 'zod'\n\nconst ${1:Resource}Schema = z.object({\n  ${2:name}: z.string().min(1),\n  ${3:description}: z.string().optional(),\n})\n\n// GET /api/${4:resources}\nexport async function GET(request: NextRequest) {\n  try {\n    const session = await auth.api.getSession({\n      headers: request.headers,\n    })\n\n    if (!session) {\n      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n    }\n\n    const ${4:resources} = await prisma.${5:resource}.findMany({\n      where: {\n        userId: session.user.id,\n      },\n      orderBy: {\n        createdAt: 'desc',\n      },\n    })\n\n    return NextResponse.json({ ${4:resources} })\n  } catch (error) {\n    return NextResponse.json(\n      { error: 'Internal Server Error' },\n      { status: 500 }\n    )\n  }\n}\n\n// POST /api/${4:resources}\nexport async function POST(request: NextRequest) {\n  try {\n    const session = await auth.api.getSession({\n      headers: request.headers,\n    })\n\n    if (!session) {\n      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n    }\n\n    const body = await request.json()\n    const validatedData = ${1:Resource}Schema.parse(body)\n\n    const ${5:resource} = await prisma.${5:resource}.create({\n      data: {\n        ...validatedData,\n        userId: session.user.id,\n      },\n    })\n\n    return NextResponse.json({ ${5:resource} }, { status: 201 })\n  } catch (error) {\n    if (error instanceof z.ZodError) {\n      return NextResponse.json(\n        { error: 'Validation Error', details: error.errors },\n        { status: 400 }\n      )\n    }\n\n    return NextResponse.json(\n      { error: 'Internal Server Error' },\n      { status: 500 }\n    )\n  }\n}",
  "scope": ["typescript"]
}

Performance Optimization Rules

1. Code Splitting and Lazy Loading

Dynamic Import Rules

{
  "name": "Dynamic Component Import",
  "description": "Generate lazy-loaded components with loading states",
  "trigger": "dynamicimport",
  "expansion": "import dynamic from 'next/dynamic'\nimport { Loader2 } from 'lucide-react'\n\nconst ${1:Component} = dynamic(() => import('@/components/${2:component-path}'), {\n  loading: () => (\n    <div className=\"flex items-center justify-center p-8\">\n      <Loader2 className=\"h-8 w-8 animate-spin\" />\n    </div>\n  ),\n  ssr: ${3:false},\n})",
  "scope": ["typescript", "tsx"]
}

2. Caching Strategies

API Caching Rules

{
  "name": "Next.js API Caching",
  "description": "Generate cached API routes with revalidation",
  "trigger": "apicache",
  "expansion": "import { NextRequest, NextResponse } from 'next/server'\nimport { unstable_cache } from 'next/cache'\n\nconst getCached${1:Data} = unstable_cache(\n  async (${2:id}: string) => {\n    // Expensive operation\n    const data = await fetch${1:Data}(${2:id})\n    return data\n  },\n  ['${3:cache-key}'],\n  {\n    revalidate: ${4:3600}, // 1 hour\n    tags: ['${5:tag}'],\n  }\n)\n\nexport async function GET(\n  request: NextRequest,\n  { params }: { params: { ${2:id}: string } }\n) {\n  try {\n    const data = await getCached${1:Data}(params.${2:id})\n    \n    return NextResponse.json({ data }, {\n      headers: {\n        'Cache-Control': 'public, s-maxage=${4:3600}, stale-while-revalidate=${6:86400}',\n      },\n    })\n  } catch (error) {\n    return NextResponse.json(\n      { error: 'Internal Server Error' },\n      { status: 500 }\n    )\n  }\n}",
  "scope": ["typescript"]
}

Testing and Quality Assurance

1. Component Testing Rules

React Testing Library Rules

{
  "name": "Component Test",
  "description": "Generate comprehensive component tests",
  "trigger": "componenttest",
  "expansion": "import { render, screen, fireEvent, waitFor } from '@testing-library/react'\nimport { vi } from 'vitest'\nimport { ${1:Component} } from '@/components/${2:component-path}'\n\n// Mock dependencies\nvi.mock('@/lib/auth-client', () => ({\n  useSession: vi.fn(() => ({\n    data: {\n      user: {\n        id: '1',\n        name: 'Test User',\n        email: 'test@example.com',\n      },\n    },\n    isPending: false,\n  })),\n}))\n\ndescribe('${1:Component}', () => {\n  it('renders correctly', () => {\n    render(<${1:Component} ${3:prop}=\"${4:value}\" />)\n    \n    expect(screen.getByText('${5:expected-text}')).toBeInTheDocument()\n  })\n\n  it('handles user interaction', async () => {\n    const mockHandler = vi.fn()\n    \n    render(<${1:Component} ${6:onAction}={mockHandler} />)\n    \n    fireEvent.click(screen.getByRole('button', { name: '${7:button-text}' }))\n    \n    await waitFor(() => {\n      expect(mockHandler).toHaveBeenCalledWith(${8:expected-args})\n    })\n  })\n\n  it('displays loading state', () => {\n    render(<${1:Component} ${9:loading}={true} />)\n    \n    expect(screen.getByText('Loading...')).toBeInTheDocument()\n  })\n\n  it('handles error state', () => {\n    render(<${1:Component} ${10:error}=\"${11:error-message}\" />)\n    \n    expect(screen.getByText('${11:error-message}')).toBeInTheDocument()\n  })\n})",
  "scope": ["typescript", "tsx"]
}

2. API Testing Rules

API Route Testing Rules

{
  "name": "API Route Test",
  "description": "Generate API route tests with auth mocking",
  "trigger": "apitest",
  "expansion": "import { NextRequest } from 'next/server'\nimport { vi } from 'vitest'\nimport { GET, POST } from '@/app/api/${1:endpoint}/route'\n\n// Mock auth\nvi.mock('@/lib/auth', () => ({\n  auth: {\n    api: {\n      getSession: vi.fn(),\n    },\n  },\n}))\n\n// Mock database\nvi.mock('@/lib/prisma', () => ({\n  prisma: {\n    ${2:model}: {\n      findMany: vi.fn(),\n      create: vi.fn(),\n      findUnique: vi.fn(),\n      update: vi.fn(),\n      delete: vi.fn(),\n    },\n  },\n}))\n\nconst mockSession = {\n  user: {\n    id: '1',\n    name: 'Test User',\n    email: 'test@example.com',\n  },\n}\n\ndescribe('/api/${1:endpoint}', () => {\n  beforeEach(() => {\n    vi.clearAllMocks()\n  })\n\n  describe('GET', () => {\n    it('returns ${2:model}s for authenticated user', async () => {\n      const mockData = [{ id: '1', name: 'Test ${3:Item}' }]\n      \n      vi.mocked(auth.api.getSession).mockResolvedValue(mockSession)\n      vi.mocked(prisma.${2:model}.findMany).mockResolvedValue(mockData)\n\n      const request = new NextRequest('http://localhost:3000/api/${1:endpoint}')\n      const response = await GET(request)\n      const data = await response.json()\n\n      expect(response.status).toBe(200)\n      expect(data.${1:endpoint}).toEqual(mockData)\n    })\n\n    it('returns 401 for unauthenticated user', async () => {\n      vi.mocked(auth.api.getSession).mockResolvedValue(null)\n\n      const request = new NextRequest('http://localhost:3000/api/${1:endpoint}')\n      const response = await GET(request)\n\n      expect(response.status).toBe(401)\n    })\n  })\n\n  describe('POST', () => {\n    it('creates new ${3:item} for authenticated user', async () => {\n      const newItem = { name: 'New ${3:Item}' }\n      const createdItem = { id: '2', ...newItem }\n      \n      vi.mocked(auth.api.getSession).mockResolvedValue(mockSession)\n      vi.mocked(prisma.${2:model}.create).mockResolvedValue(createdItem)\n\n      const request = new NextRequest('http://localhost:3000/api/${1:endpoint}', {\n        method: 'POST',\n        body: JSON.stringify(newItem),\n      })\n      \n      const response = await POST(request)\n      const data = await response.json()\n\n      expect(response.status).toBe(201)\n      expect(data.${4:item}).toEqual(createdItem)\n    })\n\n    it('validates request body', async () => {\n      vi.mocked(auth.api.getSession).mockResolvedValue(mockSession)\n\n      const request = new NextRequest('http://localhost:3000/api/${1:endpoint}', {\n        method: 'POST',\n        body: JSON.stringify({}), // Invalid data\n      })\n      \n      const response = await POST(request)\n\n      expect(response.status).toBe(400)\n    })\n  })\n})",
  "scope": ["typescript"]
}

Deployment and DevOps Rules

1. Environment Configuration

Environment Variables Rules

{
  "name": "Environment Configuration",
  "description": "Generate environment variable schemas and validation",
  "trigger": "envconfig",
  "expansion": "import { z } from 'zod'\n\nconst envSchema = z.object({\n  // Database\n  DATABASE_URL: z.string().url(),\n  \n  // Authentication\n  BETTER_AUTH_SECRET: z.string().min(32),\n  BETTER_AUTH_URL: z.string().url(),\n  \n  // OAuth Providers\n  GITHUB_CLIENT_ID: z.string().optional(),\n  GITHUB_CLIENT_SECRET: z.string().optional(),\n  GOOGLE_CLIENT_ID: z.string().optional(),\n  GOOGLE_CLIENT_SECRET: z.string().optional(),\n  \n  // App Configuration\n  NEXT_PUBLIC_APP_URL: z.string().url(),\n  NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n  \n  // Email (optional)\n  SMTP_HOST: z.string().optional(),\n  SMTP_PORT: z.string().optional(),\n  SMTP_USER: z.string().optional(),\n  SMTP_PASSWORD: z.string().optional(),\n})\n\nexport const env = envSchema.parse(process.env)\n\nexport type Env = z.infer<typeof envSchema>",
  "scope": ["typescript"]
}

2. Docker Configuration

Dockerfile Rules

{
  "name": "Next.js Dockerfile",
  "description": "Generate optimized Dockerfile for Next.js apps",
  "trigger": "dockerfile",
  "expansion": "FROM node:18-alpine AS base\n\n# Install dependencies only when needed\nFROM base AS deps\nRUN apk add --no-cache libc6-compat\nWORKDIR /app\n\n# Install dependencies based on the preferred package manager\nCOPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./\nRUN \\\n  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \\\n  elif [ -f package-lock.json ]; then npm ci; \\\n  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \\\n  else echo \"Lockfile not found.\" && exit 1; \\\n  fi\n\n# Rebuild the source code only when needed\nFROM base AS builder\nWORKDIR /app\nCOPY --from=deps /app/node_modules ./node_modules\nCOPY . .\n\n# Generate Prisma client\nRUN npx prisma generate\n\n# Build the application\nRUN yarn build\n\n# Production image, copy all the files and run next\nFROM base AS runner\nWORKDIR /app\n\nENV NODE_ENV production\n\nRUN addgroup --system --gid 1001 nodejs\nRUN adduser --system --uid 1001 nextjs\n\nCOPY --from=builder /app/public ./public\n\n# Set the correct permission for prerender cache\nRUN mkdir .next\nRUN chown nextjs:nodejs .next\n\n# Automatically leverage output traces to reduce image size\nCOPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./\nCOPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static\n\nUSER nextjs\n\nEXPOSE 3000\n\nENV PORT 3000\nENV HOSTNAME \"0.0.0.0\"\n\nCMD [\"node\", \"server.js\"]",
  "scope": ["dockerfile"]
}

Team Collaboration and Best Practices

1. Code Quality Rules

ESLint Configuration Rules

{
  "name": "ESLint Config for Stack",
  "description": "Generate comprehensive ESLint configuration",
  "trigger": "eslintstack",
  "expansion": "module.exports = {\n  extends: [\n    'next/core-web-vitals',\n    '@typescript-eslint/recommended',\n    'plugin:@typescript-eslint/recommended-requiring-type-checking',\n  ],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: './tsconfig.json',\n  },\n  plugins: ['@typescript-eslint'],\n  rules: {\n    // TypeScript specific rules\n    '@typescript-eslint/no-unused-vars': 'error',\n    '@typescript-eslint/no-explicit-any': 'warn',\n    '@typescript-eslint/prefer-const': 'error',\n    \n    // React/Next.js rules\n    'react/prop-types': 'off',\n    'react/react-in-jsx-scope': 'off',\n    'react-hooks/exhaustive-deps': 'warn',\n    \n    // Import rules\n    'import/order': [\n      'error',\n      {\n        groups: [\n          'builtin',\n          'external',\n          'internal',\n          'parent',\n          'sibling',\n          'index',\n        ],\n        'newlines-between': 'always',\n        alphabetize: {\n          order: 'asc',\n          caseInsensitive: true,\n        },\n      },\n    ],\n    \n    // General code quality\n    'no-console': 'warn',\n    'prefer-const': 'error',\n    'no-var': 'error',\n  },\n  overrides: [\n    {\n      files: ['**/*.test.ts', '**/*.test.tsx'],\n      env: {\n        jest: true,\n      },\n    },\n  ],\n}",
  "scope": ["javascript"]
}

2. Project Structure Rules

📁 Recommended Project Structure

src/
├── app/                    # Next.js App Router
│   ├── (auth)/            # Route groups
│   ├── api/               # API routes
│   └── globals.css        # Global styles
├── components/            # Reusable components
│   ├── ui/                # Shadcn/UI components
│   └── forms/             # Form components
├── lib/                   # Utility functions
│   ├── auth.ts            # BetterAuth configuration
│   ├── db.ts              # Database connection
│   └── utils.ts           # General utilities
├── hooks/                 # Custom React hooks
├── types/                 # TypeScript type definitions
└── middleware.ts          # Next.js middleware

3. Git Workflow Rules

Git Commit Message Rules

{
  "name": "Conventional Commits",
  "description": "Generate standardized commit messages",
  "trigger": "gitcommit",
  "patterns": {
    "feat": "feat(${scope}): ${description}",
    "fix": "fix(${scope}): ${description}",
    "docs": "docs(${scope}): ${description}",
    "style": "style(${scope}): ${description}",
    "refactor": "refactor(${scope}): ${description}",
    "test": "test(${scope}): ${description}",
    "chore": "chore(${scope}): ${description}"
  },
  "scopes": [
    "auth",
    "ui",
    "api",
    "db",
    "config",
    "types",
    "hooks",
    "middleware"
  ]
}

Troubleshooting Common Issues

1. Authentication Issues

⚠️ Common Auth Problems

  • CORS Issues: Ensure your BetterAuth URL matches your app URL
  • Session Persistence: Check cookie settings and domain configuration
  • Provider Setup: Verify OAuth app configurations and redirect URLs
  • Type Errors: Ensure proper TypeScript types for user sessions

Troubleshooting Steps (Bash)

# Check environment variables
echo $BETTER_AUTH_SECRET
echo $BETTER_AUTH_URL

# Verify database connection
npx prisma db pull
npx prisma generate

# Test authentication endpoints
curl -X POST http://localhost:3000/api/auth/session

# Check OAuth provider configuration
curl -X GET http://localhost:3000/api/auth/providers

2. Component Issues

🔧 Common Component Problems

  • Import Errors: Check if Shadcn components are properly installed
  • Type Mismatches: Ensure props match component interfaces
  • Styling Issues: Verify Tailwind CSS is properly configured
  • State Management: Check for proper state initialization

Component Debugging Steps (TypeScript)

// Debug component props
interface DebugProps {
  children: React.ReactNode
  componentName: string
}

function DebugComponent({ children, componentName }: DebugProps) {
  useEffect(() => {
    console.log(`${componentName} rendered`, {
      timestamp: new Date().toISOString(),
      props: { children },
    })
  }, [children, componentName])

  return <>{children}</>
}

3. Database Issues

💾 Common Database Problems

  • Migration Errors: Run npx prisma migrate dev to apply changes
  • Connection Issues: Verify DATABASE_URL in environment variables
  • Type Generation: Run npx prisma generate after schema changes
  • Seed Data: Use npx prisma db seed to populate initial data

Performance Optimization Strategies

1. Bundle Size Optimization

Bundle Analysis Rules (JavaScript)

// next.config.js
const nextConfig = {
  experimental: {
    optimizePackageImports: ['@radix-ui/react-icons'],
  },
  webpack: (config, { dev, isServer }) => {
    if (!dev && !isServer) {
      config.resolve.alias = {
        ...config.resolve.alias,
        '@radix-ui/react-icons': '@radix-ui/react-icons/dist/index.js',
      }
    }
    return config
  },
}

module.exports = nextConfig

2. Database Query Optimization

Optimized Query Patterns (TypeScript)

// Efficient data fetching with Prisma
async function getOptimizedUserData(userId: string) {
  return await prisma.user.findUnique({
    where: { id: userId },
    select: {
      id: true,
      name: true,
      email: true,
      _count: {
        select: {
          posts: true,
          comments: true,
        },
      },
    },
  })
}

// Parallel queries for better performance
async function getDashboardData(userId: string) {
  const [user, posts, stats] = await Promise.all([
    prisma.user.findUnique({ where: { id: userId } }),
    prisma.post.findMany({ 
      where: { authorId: userId },
      take: 10,
      orderBy: { createdAt: 'desc' },
    }),
    prisma.user.aggregate({
      where: { id: userId },
      _count: { posts: true },
    }),
  ])

  return { user, posts, stats }
}

Future-Proofing Your Stack

1. Upgrade Strategies

🚀 Staying Current

  • Regular Updates: Keep dependencies up to date with tools like Renovate
  • Feature Flags: Use feature flags for gradual rollouts of new features
  • Testing Coverage: Maintain high test coverage for confident upgrades
  • Migration Scripts: Create scripts for smooth database migrations

2. Scalability Considerations

Scalable Architecture Patterns (TypeScript)

// Service layer pattern
class UserService {
  constructor(private db: PrismaClient) {}

  async createUser(data: CreateUserInput): Promise<User> {
    return this.db.user.create({
      data: {
        ...data,
        id: generateId(),
        createdAt: new Date(),
      },
    })
  }

  async getUserById(id: string): Promise<User | null> {
    return this.db.user.findUnique({
      where: { id },
      include: {
        profile: true,
        settings: true,
      },
    })
  }
}

// Repository pattern
interface UserRepository {
  create(data: CreateUserInput): Promise<User>
  findById(id: string): Promise<User | null>
  findByEmail(email: string): Promise<User | null>
  update(id: string, data: UpdateUserInput): Promise<User>
  delete(id: string): Promise<void>
}

Summary and Next Steps

Through this comprehensive guide, you've learned how to leverage Cursor Rules to supercharge your development workflow with the Next.js + Shadcn/UI + TypeScript + BetterAuth stack. Here's your roadmap to mastery:

🎯 Immediate Actions

  1. Install the Stack: Set up a new project with all four technologies
  2. Configure Cursor Rules: Implement the essential rules from this guide
  3. Build Your First App: Create a simple authenticated application
  4. Establish Patterns: Use the component and API patterns consistently

📈 Advanced Implementation

  1. Optimize Performance: Implement caching, lazy loading, and bundle optimization
  2. Enhance Testing: Add comprehensive test coverage with the provided patterns
  3. Scale Architecture: Apply service and repository patterns for larger applications
  4. Deploy with Confidence: Use the Docker and deployment configurations

🤝 Community and Collaboration

  1. Share Rules: Contribute your custom Cursor Rules to the community
  2. Stay Updated: Follow the latest developments in each technology
  3. Contribute Back: Help improve the tools and libraries you use
  4. Mentor Others: Share your knowledge with fellow developers

✅ Key Takeaways

Mastering this tech stack with Cursor Rules transforms your development experience from manual repetition to intelligent automation. You gain not just speed, but consistency, quality, and the confidence to build scalable, maintainable applications. The combination of Next.js flexibility, Shadcn/UI beauty, TypeScript safety, and BetterAuth security creates a foundation for any modern web application.

Further Reading

  • Next.js Documentation
  • Shadcn/UI Component Library
  • TypeScript Handbook
  • BetterAuth Documentation
  • Cursor Editor Rules Guide
  • Advanced Cursor Techniques

This comprehensive guide will be continuously updated to reflect the latest features and best practices in the Next.js, Shadcn/UI, TypeScript, and BetterAuth ecosystem.

Cursor Coding Rules for Next.js Apps: Complete Development Guide
nextjs

Cursor Coding Rules for Next.js Apps: Complete Development Guide

Master Next.js development with intelligent Cursor coding rules. Learn app router patterns, server components, API routes, and best practices to accelerate your Next.js project development with AI assistance.

2025-08-3018 min read
2. Data Table Components
3. Dialog and Modal Patterns
TypeScript Integration Rules
1. Type Definitions and Interfaces
2. Custom Hooks with TypeScript
BetterAuth Integration Rules
1. Authentication Setup
2. Authentication Components
Real-World Application Examples
Example 1: E-commerce Product Dashboard
Cursor Rules Assistance Process
Example 2: User Profile Management
Advanced Integration Patterns
1. Middleware and Route Protection
2. Database Integration with Prisma
3. API Route Patterns
Performance Optimization Rules
1. Code Splitting and Lazy Loading
2. Caching Strategies
Testing and Quality Assurance
1. Component Testing Rules
2. API Testing Rules
Deployment and DevOps Rules
1. Environment Configuration
2. Docker Configuration
Team Collaboration and Best Practices
1. Code Quality Rules
2. Project Structure Rules
📁 Recommended Project Structure
3. Git Workflow Rules
Troubleshooting Common Issues
1. Authentication Issues
⚠️ Common Auth Problems
2. Component Issues
🔧 Common Component Problems
3. Database Issues
💾 Common Database Problems
Performance Optimization Strategies
1. Bundle Size Optimization
2. Database Query Optimization
Future-Proofing Your Stack
1. Upgrade Strategies
🚀 Staying Current
2. Scalability Considerations
Summary and Next Steps
🎯 Immediate Actions
📈 Advanced Implementation
🤝 Community and Collaboration
✅ Key Takeaways
Further Reading

About the Author

C
Cursor Rules Pro Team
Expert Development Team

Expert developer passionate about modern web technologies and AI-assisted development.

Popular Tags

betterauth
cursor
fullstack
nextjs
productivity
shadcn
typescript
cursor

Stay Updated

Get the latest articles and tutorials delivered to your inbox.