Development Environment
Setting up and troubleshooting local development environment issues.
Development Environment
Guide to setting up and troubleshooting your local development environment.
Environment Setup
Node.js and npm Issues
Version Management:
# Check Node.js version
node --version
npm --version
# Use Node Version Manager (nvm)
# Install nvm (Linux/Mac)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Install and use specific Node.js version
nvm install 18
nvm use 18
nvm alias default 18
# Windows - use nvm-windows
# Download from: https://github.com/coreybutler/nvm-windows
# Check installed versions
nvm list
# Use project-specific Node.js version
# Create .nvmrc file
echo "18.17.0" > .nvmrc
nvm use
Package Management Issues:
# Clear npm cache
npm cache clean --force
# Delete node_modules and reinstall
rm -rf node_modules package-lock.json
npm install
# Fix permission issues (Linux/Mac)
sudo chown -R $(whoami) ~/.npm
sudo chown -R $(whoami) /usr/local/lib/node_modules
# Use npm audit to fix vulnerabilities
npm audit
npm audit fix
npm audit fix --force
# Update all packages
npm update
npx npm-check-updates -u
npm install
Environment Variables Configuration
# Create environment files
touch .env.local
touch .env.development
touch .env.production
# .env.local (for local development)
NEXT_PUBLIC_SUPABASE_URL=your_local_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_local_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
# Database URL for local development
DATABASE_URL=postgresql://postgres:password@localhost:54322/postgres
# Development flags
NEXT_PUBLIC_DEBUG=true
NEXT_PUBLIC_ENVIRONMENT=development
Environment Variable Validation:
// lib/env.ts
import { z } from 'zod'
const envSchema = z.object({
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
SUPABASE_SERVICE_ROLE_KEY: z.string().min(1),
DATABASE_URL: z.string().url().optional(),
NEXT_PUBLIC_DEBUG: z.string().optional(),
})
export const env = envSchema.parse(process.env)
// Type-safe environment variables
declare global {
namespace NodeJS {
interface ProcessEnv extends z.infer<typeof envSchema> {}
}
}
IDE Configuration
VS Code Setup
Essential Extensions:
// .vscode/extensions.json
{
"recommendations": [
"ms-vscode.vscode-typescript-next",
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode",
"ms-vscode.vscode-eslint",
"ms-vscode.vscode-json",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense",
"ms-vscode.vscode-todo-highlight",
"gruntfuggly.todo-tree"
]
}
VS Code Settings:
// .vscode/settings.json
{
"typescript.preferences.importModuleSpecifier": "relative",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.associations": {
"*.mdx": "markdown"
},
"emmet.includeLanguages": {
"javascript": "javascriptreact",
"typescript": "typescriptreact"
},
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
}
Debug Configuration:
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node",
"request": "attach",
"port": 9229,
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug full stack",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/next",
"args": ["dev"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"],
"env": {
"NODE_OPTIONS": "--inspect"
}
}
]
}
Development Tools Setup
Package.json Scripts:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "next lint --fix",
"type-check": "tsc --noEmit",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"clean": "rm -rf .next out node_modules/.cache",
"reset": "npm run clean && rm -rf node_modules package-lock.json && npm install",
"analyze": "cross-env ANALYZE=true npm run build"
}
}
Database Development Setup
Local Supabase Setup
# Install Supabase CLI
npm install -g supabase
# Initialize Supabase project
supabase init
# Start local development
supabase start
# Check status
supabase status
# Stop local instance
supabase stop
# Reset database
supabase db reset
# Generate types
supabase gen types typescript --local > types/database.ts
Supabase Configuration:
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
import type { Database } from '@/types/database'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient<Database>(supabaseUrl, supabaseKey, {
auth: {
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
})
// Development-only admin client
export const supabaseAdmin = createClient<Database>(
supabaseUrl,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
autoRefreshToken: false,
persistSession: false,
},
}
)
Database Migrations
-- Create migration file
-- supabase/migrations/20240101000000_initial_schema.sql
-- Enable necessary extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Create tables
CREATE TABLE products (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
name VARCHAR(255) NOT NULL,
sku VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
price DECIMAL(10,2) NOT NULL,
is_active BOOLEAN DEFAULT true,
user_id UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create RLS policies
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view their own products" ON products
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own products" ON products
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Create indexes
CREATE INDEX idx_products_user_id ON products(user_id);
CREATE INDEX idx_products_sku ON products(sku);
CREATE INDEX idx_products_is_active ON products(is_active);
-- Create function to update updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- Create trigger
CREATE TRIGGER update_products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
Development Workflow
Git Configuration
# Configure Git
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Set up Git hooks
npx husky install
npx husky add .husky/pre-commit "npm run lint && npm run type-check"
npx husky add .husky/commit-msg "npx commitlint --edit $1"
.gitignore for Next.js:
# Dependencies
/node_modules
/.pnp
.pnp.js
# Testing
/coverage
# Next.js
/.next/
/out/
# Production
/build
# Environment files
.env*.local
.env.production
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Local
.DS_Store
*.tsbuildinfo
next-env.d.ts
# Supabase
.branches
.temp
# IDE
.vscode/settings.json
.idea
Linting and Formatting
ESLint Configuration:
// eslint.config.mjs
import { dirname } from "path"
import { fileURLToPath } from "url"
import { FlatCompat } from "@eslint/eslintrc"
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
})
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
{
rules: {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "warn",
"prefer-const": "error",
"no-var": "error",
},
},
]
export default eslintConfig
Prettier Configuration:
// prettier.config.cjs
module.exports = {
semi: false,
trailingComma: "es5",
singleQuote: true,
tabWidth: 2,
useTabs: false,
printWidth: 80,
endOfLine: "lf",
plugins: ["prettier-plugin-tailwindcss"],
}
Debugging Techniques
Browser DevTools
// Debug helpers
export const debug = {
log: (message: string, data?: any) => {
if (process.env.NEXT_PUBLIC_DEBUG === 'true') {
console.log(`[DEBUG] ${message}`, data)
}
},
table: (data: any) => {
if (process.env.NEXT_PUBLIC_DEBUG === 'true') {
console.table(data)
}
},
time: (label: string) => {
if (process.env.NEXT_PUBLIC_DEBUG === 'true') {
console.time(label)
}
},
timeEnd: (label: string) => {
if (process.env.NEXT_PUBLIC_DEBUG === 'true') {
console.timeEnd(label)
}
},
}
// React DevTools debugging
export function useDebugValue(value: any, formatter?: (value: any) => any) {
if (process.env.NODE_ENV === 'development') {
React.useDebugValue(value, formatter)
}
}
Network Debugging
// API debugging middleware
export function debugApiCall(url: string, options?: RequestInit) {
debug.log(`API Call: ${options?.method || 'GET'} ${url}`)
debug.time(`API-${url}`)
return fetch(url, options)
.then(response => {
debug.timeEnd(`API-${url}`)
debug.log(`API Response: ${response.status} ${response.statusText}`)
return response
})
.catch(error => {
debug.timeEnd(`API-${url}`)
debug.log(`API Error: ${error.message}`)
throw error
})
}
Performance Monitoring
Development Performance Tools
// Performance monitoring in development
export function usePerformanceMonitor() {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
// Monitor component render times
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
debug.log(`Performance: ${entry.name} took ${entry.duration}ms`)
}
})
observer.observe({ entryTypes: ['measure'] })
return () => observer.disconnect()
}
}, [])
}
// Bundle size monitoring
export function analyzeBundleSize() {
if (process.env.NODE_ENV === 'development') {
import('webpack-bundle-analyzer').then(({ BundleAnalyzerPlugin }) => {
// Add to webpack config for development analysis
})
}
}
Common Development Issues
Port Already in Use
# Find and kill process using port 3000
lsof -ti:3000 | xargs kill -9
# Or use different port
npm run dev -- -p 3001
Permission Denied
# Fix npm permissions (Mac/Linux)
sudo chown -R $(whoami) ~/.npm
sudo chown -R $(whoami) /usr/local/lib/node_modules
Module Resolution Issues
// tsconfig.json path mapping
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"],
"@/types/*": ["./src/types/*"]
}
}
}
For advanced development environment configurations, refer to the Next.js Documentation and VS Code Documentation.