A modern Next.js 14 template with TypeScript, Tailwind CSS, ShadCN UI, Zod validation, Biome tooling, and comprehensive testing setup.
- Next.js 14 - App Router, Server Components, and latest features
- React 18 - Latest React features with concurrent rendering
- TypeScript 5 - Strong typing and modern language features
- Tailwind CSS - Utility-first CSS framework
- ShadCN UI - Beautiful components built with Radix UI and Tailwind CSS
- TanStack Query - Powerful server state management with caching, background updates, and more
- Supabase - Complete backend with authentication, database, and real-time features
- Zod - Schema validation for forms and API routes
- Biome - Fast formatter and linter (replaces ESLint + Prettier)
- Vitest - Lightning fast unit testing with React Testing Library
- Error Handling - Comprehensive error boundaries, 404 pages, and loading states
This template includes ready-to-use ShadCN components:
- Button - Multiple variants (default, destructive, outline, secondary, ghost, link)
- Card - Complete card system with header, content, and footer
- Input - Form input with proper styling
- Label - Accessible form labels
All components are fully typed, tested, and follow accessibility best practices.
-
Install dependencies:
pnpm install
-
Start development server:
pnpm dev
-
Open your browser: Navigate to
http://localhost:3000
βββ app/ # Next.js App Router
β βββ api/ # API routes
β βββ error.tsx # Error boundary UI
β βββ loading.tsx # Loading UI
β βββ not-found.tsx # 404 page
β βββ layout.tsx # Root layout
β βββ page.tsx # Home page
β βββ globals.css # Global styles with ShadCN tokens
βββ components/
β βββ ui/ # ShadCN UI components
β β βββ button.tsx # Button component
β β βββ card.tsx # Card components
β β βββ input.tsx # Input component
β β βββ label.tsx # Label component
β βββ examples/ # Example components
β β βββ posts-example.tsx # TanStack Query demo
β βββ forms/ # Form components
β βββ layout/ # Layout components
βββ providers/
β βββ query-provider.tsx # TanStack Query provider
βββ lib/
β βββ utils.ts # Utility functions (cn helper)
β βββ validations.ts # Zod schemas
βββ types/ # TypeScript type definitions
βββ tests/ # Test configuration
βββ hooks/ # Custom React hooks
βββ use-posts.ts # TanStack Query example hook
This template includes comprehensive testing setup:
- Unit Tests: Component and function testing
- Integration Tests: API route testing
- UI Testing: React Testing Library for user interactions
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with UI
pnpm test:ui
# Generate coverage report
pnpm test:coverage
Tests are co-located with source files:
components/ui/button.test.tsx
- Button component testscomponents/ui/card.test.tsx
- Card component testsapp/page.test.tsx
- Home page testsapp/error.test.tsx
- Error boundary testsapp/loading.test.tsx
- Loading UI testslib/validations.test.ts
- Validation schema testsapp/api/users/route.test.ts
- API route tests
The template uses ShadCN's design system with:
- CSS Variables - For theming and customization
- Dark Mode - Built-in dark mode support
- Component Variants - Multiple styles for each component
- Responsive Design - Mobile-first approach
Use the ShadCN CLI to add new components:
npx shadcn-ui@latest add [component-name]
Modify the design tokens in:
app/globals.css
- CSS variablestailwind.config.ts
- Tailwind configuration
- Formatting:
pnpm format
- Linting:
pnpm lint
- Check:
pnpm check
(format + lint)
biome.json
- Biome configurationvitest.config.ts
- Test configurationtailwind.config.ts
- Tailwind configurationtsconfig.json
- TypeScript configuration
- app/error.tsx - Catches JavaScript errors in route segments
- app/not-found.tsx - Custom 404 page
- app/loading.tsx - Loading UI with skeleton states
- Automatic error logging and user-friendly interfaces
- Skeleton Loading - Matches your page layout structure
- Loading Spinner - Animated spinner with backdrop
- Responsive Design - Works on all screen sizes
- Accessibility - Screen reader friendly loading states
- Smooth Animations - Pulse and spin animations using Tailwind
- Development Mode - Shows detailed error information
- Production Mode - User-friendly error messages
- Recovery Options - Reset error boundary or navigate home
- Accessibility - Proper ARIA attributes and keyboard navigation
TanStack Query is configured for powerful server state management with:
- Automatic Caching - Intelligent request deduplication and caching
- Background Refetching - Keep data fresh with background updates
- Loading & Error States - Built-in loading and error handling
- DevTools - Debug queries with React Query DevTools
- Optimistic Updates - Immediate UI updates for better UX
// hooks/use-posts.ts
import { useQuery } from '@tanstack/react-query'
export function usePosts() {
return useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 5 * 60 * 1000, // 5 minutes
})
}
// components/posts-example.tsx
import { usePosts } from '@/hooks/use-posts'
export function PostsExample() {
const { data, isLoading, error, refetch } = usePosts()
// Component implementation...
}
Supabase is configured for complete backend functionality with:
- Authentication - Email/password, OAuth (Google, GitHub, etc.), magic links
- Database - PostgreSQL with real-time subscriptions
- Row Level Security - Secure data access patterns
- Edge Functions - Server-side logic at the edge
- Storage - File uploads and management
-
Create a Supabase project at supabase.com
-
Add environment variables to
.env.local
:NEXT_PUBLIC_SUPABASE_URL=your-supabase-url NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key
-
Set up authentication redirect URLs in your Supabase dashboard:
- Development:
http://localhost:3000/auth/callback
- Production:
https://yourdomain.com/auth/callback
- Development:
// Using the auth provider
import { useAuth } from '@/providers/auth-provider'
export function MyComponent() {
const { user, loading, signOut } = useAuth()
if (loading) return <div>Loading...</div>
if (!user) return <LoginForm />
return (
<div>
<p>Welcome, {user.email}!</p>
<button onClick={signOut}>Sign Out</button>
</div>
)
}
// Direct Supabase client usage
import { createSupabaseClient } from '@/lib/supabase'
const supabase = createSupabaseClient()
// Sign up
const { error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'password',
options: {
data: { full_name: 'John Doe' }
}
})
// Sign in
const { error } = await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'password'
})
// OAuth sign in
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
})
// Fetch data
const { data, error } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
// Insert data
const { data, error } = await supabase
.from('posts')
.insert({ title: 'Hello World', content: 'My first post' })
.select()
// Real-time subscriptions
const subscription = supabase
.channel('posts')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => console.log('Change received!', payload)
)
.subscribe()
Pre-built authentication components:
- LoginForm - Email/password login with OAuth options
- SignupForm - User registration with email confirmation
- AuthModal - Modal that switches between login/signup
- UserProfile - Display user information and logout
- AuthExample - Complete authentication demo
-- Enable RLS (Row Level Security)
alter table posts enable row level security;
-- Create a table
create table posts (
id uuid default gen_random_uuid() primary key,
title text not null,
content text,
user_id uuid references auth.users not null,
created_at timestamp with time zone default timezone('utc'::text, now()) not null
);
-- Create RLS policies
create policy "Users can insert their own posts" on posts for insert with check (auth.uid() = user_id);
create policy "Users can view all posts" on posts for select using (true);
create policy "Users can update their own posts" on posts for update using (auth.uid() = user_id);
create policy "Users can delete their own posts" on posts for delete using (auth.uid() = user_id);
@supabase/ssr
for the latest features and security updates.
To use the latest Supabase auth helpers:
-
Replace dependencies in
package.json
:pnpm remove @supabase/auth-helpers-nextjs @supabase/auth-helpers-react pnpm add @supabase/ssr
-
Update
lib/supabase.ts
to use the new SSR helpers -
Follow the Supabase SSR guide for migration details
Example API route with Zod validation:
// app/api/users/route.ts
import { createUserSchema } from '@/lib/validations'
export async function POST(request: Request) {
const body = await request.json()
const validatedData = createUserSchema.parse(body)
// Handle validated data
}
Create a .env.local
file in your project root:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key
const { data, isLoading, error, refetch } = usePosts()
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading posts</div>
return (
<div>
{data?.posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
<button onClick={() => refetch()}>Refresh</button>
</div>
)
}
The app is wrapped with QueryProvider in app/layout.tsx
:
import { QueryProvider } from '@/providers/query-provider'
export default function RootLayout({ children }) {
return (
<html>
<body>
<QueryProvider>
{children}
</QueryProvider>
</body>
</html>
)
}
TanStack Query DevTools are automatically included in development mode. Look for the React Query logo in the bottom-left corner of your browser.
Example API route with Zod validation:
// app/api/users/route.ts
import { createUserSchema } from '@/lib/validations'
export async function POST(request: Request) {
const body = await request.json()
const validatedData = createUserSchema.parse(body)
// Handle validated data
}
- Next.js Documentation
- ShadCN UI
- Tailwind CSS
- Zod Documentation
- Vitest Documentation
- Biome Documentation
MIT License - feel free to use this template for your projects!