Skip to content

Instantly share code, notes, and snippets.

@dikaio
Created May 14, 2025 19:04
Show Gist options
  • Save dikaio/afb4851dba7e9076ab75eee71bde220e to your computer and use it in GitHub Desktop.
Save dikaio/afb4851dba7e9076ab75eee71bde220e to your computer and use it in GitHub Desktop.
Global claude code preferences e.g. ~/.claude/CLAUDE.md

Claude Code Preferences

Technology Versions

  • Next.js: 15.x
  • TypeScript: 5.x
  • React: 19.x
  • Tailwind CSS: 4.x
  • Node.js: 22.x LTS

Table of Contents

  1. Session Management
  2. Clean Code
  3. TypeScript
  4. Next.js
  5. Tailwind CSS
  6. AI Development
  7. Security
  8. Testing
  9. Documentation
  10. Performance
  11. State Management
  12. Error Handling
  13. Deployment & DevOps
  14. Accessibility
  15. Internationalization

Session Management

At the start of each session:

  1. Review the project's @README.md file to understand the current context
  2. Review open tasks in @TODO.md to identify work items

During the session:

  • Mark tasks as completed in @TODO.md as they are finished
  • Add notes about implementation details or decisions made

At the end of each session:

  1. Review @TODO.md and update task statuses
  2. Document any new tasks discovered
  3. Add any follow-up items for the next session

Clean Code

Constants Over Magic Numbers

  • Replace hard-coded values with named constants
  • Use descriptive constant names that explain the value's purpose
  • Keep constants at the top of the file or in a dedicated constants file

Meaningful Names

  • Variables, functions, and classes should reveal their purpose
  • Names should explain why something exists and how it's used
  • Avoid abbreviations unless they're universally understood

Smart Comments

  • Don't comment on what the code does - make the code self-documenting
  • Use comments to explain why something is done a certain way
  • Document APIs, complex algorithms, and non-obvious side effects

Single Responsibility

  • Each function should do exactly one thing
  • Functions should be small and focused
  • If a function needs a comment to explain what it does, it should be split

DRY (Don't Repeat Yourself)

  • Extract repeated code into reusable functions
  • Share common logic through proper abstraction
  • Maintain single sources of truth

Clean Structure

  • Keep related code together
  • Organize code in a logical hierarchy
  • Use consistent file and folder naming conventions

Encapsulation

  • Hide implementation details
  • Expose clear interfaces
  • Move nested conditionals into well-named functions

Code Quality Maintenance

  • Refactor continuously
  • Fix technical debt early
  • Leave code cleaner than you found it

Testing

  • Write tests before fixing bugs
  • Keep tests readable and maintainable
  • Test edge cases and error conditions

Version Control

  • Write clear commit messages
  • Make small, focused commits
  • Use meaningful branch names

TypeScript

Type System

  • Prefer interfaces over types for object definitions
  • Use type for unions, intersections, and mapped types
  • Avoid using any, prefer unknown for unknown types
  • Use strict TypeScript configuration
  • Leverage TypeScript's built-in utility types
  • Use generics for reusable type patterns

TypeScript Configuration

{
  "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,
    "baseUrl": ".",
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Naming Conventions

  • Use PascalCase for type names and interfaces
  • Use camelCase for variables and functions
  • Use UPPER_CASE for constants
  • Use descriptive names with auxiliary verbs (e.g., isLoading, hasError)
  • Prefix interfaces for React props with 'Props' (e.g., ButtonProps)

Code Organization

  • Keep type definitions close to where they're used
  • Export types and interfaces from dedicated type files when shared
  • Use barrel exports (index.ts) for organizing exports
  • Place shared types and interfaces in their respective directories
    • src/types/index.ts
    • src/interfaces/index.ts
  • Co-locate component props with their components

Functions

  • Use explicit return types for public functions
  • Use arrow functions for callbacks and methods
  • Implement proper error handling with custom error types
  • Use function overloads for complex type scenarios
  • Prefer async/await over Promises

Best Practices

  • Enable strict mode in tsconfig.json
  • Use readonly for immutable properties
  • Leverage discriminated unions for type safety
  • Use type guards for runtime type checking
  • Implement proper null checking
  • Avoid type assertions unless necessary

Error Handling

  • Create custom error types for domain-specific errors
  • Use Result types for operations that can fail
  • Implement proper error boundaries
  • Use try-catch blocks with typed catch clauses
  • Handle Promise rejections properly

Patterns

  • Use the Builder pattern for complex object creation
  • Implement the Repository pattern for data access
  • Use the Factory pattern for object creation
  • Leverage dependency injection
  • Use the Module pattern for encapsulation

Next.js

Project Structure

// Example of a well-structured Next.js page
import { Metadata } from 'next'
import { Suspense } from 'react'
import { ErrorBoundary } from '@/components/error-boundary'
import { LoadingSpinner } from '@/components/ui/loading-spinner'

export const metadata: Metadata = {
  title: 'Page Title',
  description: 'Page description',
}

export default async function Page() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<LoadingSpinner />}>
        <main className="container mx-auto px-4">
          {/* Page content */}
        </main>
      </Suspense>
    </ErrorBoundary>
  )
}

Data Fetching Patterns

// Example of proper data fetching with error handling
async function getData() {
  try {
    const res = await fetch('https://api.example.com/data', {
      next: { revalidate: 3600 }, // Revalidate every hour
      headers: {
        'Content-Type': 'application/json',
      },
    })
    
    if (!res.ok) {
      throw new Error(`HTTP error! status: ${res.status}`)
    }
    
    return res.json()
  } catch (error) {
    console.error('Error fetching data:', error)
    throw error
  }
}

Error Handling Pattern

// Example of proper error handling
'use client'

import { useEffect } from 'react'
import { useRouter } from 'next/navigation'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error)
  }, [error])

  return (
    <div className="flex min-h-screen flex-col items-center justify-center">
      <h2 className="text-2xl font-bold">Something went wrong!</h2>
      <button
        className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-white"
        onClick={() => reset()}
      >
        Try again
      </button>
    </div>
  )
}

Component Organization

  • Route-Specific Components: Place directly in the route folder they belong to
  • Shared Feature Components: Group in feature folders within the main components directory
  • UI Components: Place generic, widely-used components in components/ui
  • Feature-First Organization: Prioritize grouping by feature over component type
  • Co-location Principle: Keep related code close together
  • Clear Import Paths: Use consistent import paths for better discoverability

Naming Conventions

  • Use descriptive names with auxiliary verbs (isLoading, hasError)
  • Prefix event handlers with "handle" (handleClick, handleSubmit)
  • Use lowercase with dashes for directories (components/auth-wizard)
  • For all components that are nonroutable, favor named exports for components

Routable:

export default NewsPage = () => {
	return <div>News</div>;
};

Nonroutable:

const NewsFeed = () => {
	return <div>News Feed</div>;
};

export { NewsFeed };

Components

  • Use Server Components by default
  • Mark client components explicitly with 'use client'
  • Wrap client components in Suspense with fallback
  • Use dynamic loading for non-critical components
  • Implement proper error boundaries
  • Place static content and interfaces at end of file
  • Keep data fetching logic colocated
  • Leverage shadcn/ui hooks and components
  • Follow Radix UI's accessibility patterns
  • Implement proper state management

Performance

  • Optimize images: Use WebP format, size data, lazy loading
  • Minimize use of 'useEffect' and 'setState'
  • Favor Server Components (RSC) where possible
  • Use dynamic loading for non-critical components
  • Implement proper caching strategies
  • Optimize images (Avif, WebP, sizing, lazy loading)
  • Implement code splitting
  • Use next/font for font optimization
  • Configure staleTimes for client-side router cache
  • Monitor Core Web Vitals

Data Fetching

  • Use Server Components for data fetching when possible
  • Implement proper error handling for data fetching
  • Handle loading and error states appropriately
  • Fetch requests are no longer cached by default
  • Use appropriate caching strategies
  • Use cache: 'force-cache' for specific cached requests unless using basehub
  • Implement fetchCache = 'default-cache' for layout/page-level caching
// Cached route handler example
export const dynamic = 'force-static'

export async function GET(request: Request) {
  const params = await request.params
  // Implementation
}

Routing

  • Use the App Router conventions
  • Implement proper loading and error states for routes
  • Use dynamic routes appropriately
  • Handle parallel routes when needed

Forms and Validation

  • Define schemas using Zod's type-safe API
  • Implement custom validation logic using Zod's refine method
  • Use Zod's inferred types for TypeScript integration
  • Utilize Zod's superRefine for complex validation scenarios
  • Implement proper server-side validation
  • Handle form errors appropriately
  • Show loading states during form submission

Error Handling

  • Implement proper error boundaries
  • Return appropriate HTTP status codes
  • Provide meaningful error messages
  • Log errors appropriately
  • Handle edge cases gracefully
  • Use shadcn/ui alerts and toasts
  • Implement proper error boundaries
  • Handle API errors consistently
  • Provide meaningful error messages
// app/components/errors/error-alert.tsx
import { AlertCircle } from "lucide-react";
import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/ui/alert";

function ErrorAlert({ title, description }) {
  return (
    <Alert variant="destructive">
      <AlertCircle className="h-4 w-4" />
      <AlertTitle>{title}</AlertTitle>
      <AlertDescription>{description}</AlertDescription>
    </Alert>
  );
}
export { ErrorAlert };

State Management

Server State

// Example of using React Query for server state
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'

function TodoList() {
  const queryClient = useQueryClient()
  
  const { data: todos, isLoading } = useQuery({
    queryKey: ['todos'],
    queryFn: () => fetch('/api/todos').then(res => res.json())
  })
  
  const mutation = useMutation({
    mutationFn: (newTodo) => {
      return fetch('/api/todos', {
        method: 'POST',
        body: JSON.stringify(newTodo)
      })
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    }
  })
  
  if (isLoading) return <div>Loading...</div>
  
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

Client State

// Example of using Zustand for client state
import create from 'zustand'

interface Store {
  count: number
  increment: () => void
  decrement: () => void
}

const useStore = create<Store>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 }))
}))

function Counter() {
  const { count, increment, decrement } = useStore()
  
  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  )
}

URL State

// Example of using URL state with nuqs
'use client'

import { useQueryState } from 'nuqs'

function SearchFilters() {
  const [search, setSearch] = useQueryState('search')
  const [page, setPage] = useQueryState('page')
  
  return (
    <div>
      <input
        value={search || ''}
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Search..."
      />
      <button onClick={() => setPage((p) => (p ? Number(p) + 1 : 1))}>
        Next Page
      </button>
    </div>
  )
}

Performance Optimization

Component Optimization

// Example of optimized component with memo and useCallback
import { memo, useCallback } from 'react'

interface ButtonProps {
  onClick: () => void
  children: React.ReactNode
}

const Button = memo(function Button({ onClick, children }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className="rounded-md bg-blue-500 px-4 py-2 text-white"
    >
      {children}
    </button>
  )
})

function ParentComponent() {
  const handleClick = useCallback(() => {
    console.log('Button clicked')
  }, [])
  
  return <Button onClick={handleClick}>Click me</Button>
}

Data Fetching Optimization

// Example of optimized data fetching with SWR
import useSWR from 'swr'

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher, {
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
    dedupingInterval: 2000,
    refreshInterval: 0
  })
  
  if (error) return <div>Failed to load</div>
  if (isLoading) return <div>Loading...</div>
  
  return <div>Hello {data.name}!</div>
}

Image Optimization

// Example of optimized image loading
import Image from 'next/image'

function OptimizedGallery() {
  return (
    <div className="grid grid-cols-3 gap-4">
      {images.map((image) => (
        <div key={image.id} className="relative aspect-square">
          <Image
            src={image.url}
            alt={image.alt}
            fill
            sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
            className="object-cover"
            loading="lazy"
            quality={75}
          />
        </div>
      ))}
    </div>
  )
}

Bundle Optimization

// Example of dynamic imports for code splitting
import dynamic from 'next/dynamic'

const DynamicChart = dynamic(() => import('@/components/Chart'), {
  loading: () => <p>Loading chart...</p>,
  ssr: false
})

const DynamicMap = dynamic(() => import('@/components/Map'), {
  loading: () => <p>Loading map...</p>,
  ssr: false
})

function Dashboard() {
  return (
    <div>
      <DynamicChart />
      <DynamicMap />
    </div>
  )
}

Tailwindcss

Tailwindcss Best Practices

  • Follow naming conventions
  • Keep styles organized
  • Use the latest documentation
  • Follow accessibility guidelines

Components

  • Use shadcn/ui components when available
  • Extend components properly
  • Keep component variants consistent
  • Implement proper animations
  • Use proper transition utilities
  • Keep accessibility in mind

Component Styling

  • Use utility classes over custom CSS
  • Group related utilities with @apply when needed
  • Use proper responsive design utilities
  • Implement dark mode properly
  • Use proper state variants
  • Keep component styles consistent

Layout

  • Use Flexbox and Grid utilities effectively
  • Implement proper spacing system
  • Use container queries when needed
  • Implement proper responsive breakpoints
  • Use proper padding and margin utilities
  • Implement proper alignment utilities

Typography

  • Use proper font size utilities
  • Implement proper line height
  • Use proper font weight utilities
  • Configure custom fonts properly
  • Use proper text alignment
  • Implement proper text decoration

Colors

  • Use semantic color naming
  • Implement proper color contrast
  • Use opacity utilities effectively
  • Configure custom colors properly
  • Use proper gradient utilities
  • Implement proper hover states

Responsive Design

  • Use mobile-first approach
  • Implement proper breakpoints
  • Use container queries effectively
  • Handle different screen sizes properly
  • Implement proper responsive typography
  • Use proper responsive spacing

Tailwindcss Performance

  • Use proper purge configuration
  • Minimize custom CSS
  • Use proper caching strategies
  • Implement proper code splitting
  • Optimize for production
  • Monitor bundle size

AI

AI Agents Best Practices

  • Find the simplest solution possible
  • When more complexity is warranted, use a workflow
  • Make use of augmentation to provide context to the LLM e.g. Retrieval, Tools, Memory.
  • Ensure each Agent provides an easy, well-documented interface for the LLM
  • Use the correct LLM for the Agents domain

AI Workflow Best Practices

  • Find the simplest solution possible
  • When more complexity is warranted, use a workflow
  • Use prompt chaining when tasks are easily and cleanly decomposed into fixed subtasks
    • Generating Marketing copy, then translating it into a different language.
    • Writing an outline of a document, checking that the outline meets certain criteria, then writing the document based on the outline.
  • Use routing workflows for complex tasks
    • Directing different types of customer service queries (general questions, refund requests, technical support) into different downstream processes, prompts, and tools.
    • Routing easy/common questions to smaller models like Claude 3.5 Haiku and hard/unusual questions to more capable models like Claude 3.5 Sonnet to optimize cost and speed.
  • Use parallelization when the divided subtasks can be parallelized for speed, or when multiple perspectives or attempts are needed for higher confidence results.
    • Implementing guardrails where one model instance processes user queries while another screens them for inappropriate content or requests. This tends to perform better than having the same LLM call handle both guardrails and the core response.
    • Automating evals for evaluating LLM performance, where each LLM call evaluates a different aspect of the model's performance on a given prompt.
    • Reviewing a piece of code for vulnerabilities, where several different prompts review and flag the code if they find a problem.
    • Evaluating whether a given piece of content is inappropriate, with multiple prompts evaluating different aspects or requiring different vote thresholds to balance false positives and negatives.
  • Use orchestrator-workers for complex tasks where you can't predict the subtasks needed, where subtasks aren't pre-defined, but determined by the orchestrator based on the specific input.
    • Coding products that make complex changes to multiple files each time.
    • Search tasks that involve gathering and analyzing information from multiple sources for possible relevant information.
  • Use evaluator-optimizer when we have clear evaluation criteria, and when iterative refinement provides measurable value.
    • Literary translation where there are nuances that the translator LLM might not capture initially, but where an evaluator LLM can provide useful critiques.
    • Complex search tasks that require multiple rounds of searching and analysis to gather comprehensive information, where the evaluator decides whether further searches are warranted.

AI Tools Best Practices

  • Find the simplest solution possible

Security

Authentication & Authorization

  • Implement proper authentication using NextAuth.js or similar
  • Use role-based access control (RBAC)
  • Implement proper session management
  • Use secure password hashing (bcrypt)
  • Implement rate limiting
  • Use CSRF protection
  • Implement proper CORS policies

Data Security

  • Encrypt sensitive data at rest
  • Use environment variables for secrets
  • Implement proper input validation
  • Use parameterized queries to prevent SQL injection
  • Implement proper XSS protection
  • Use Content Security Policy (CSP)
  • Implement proper file upload security

API Security

  • Use proper API authentication
  • Implement request validation
  • Use rate limiting
  • Implement proper error handling
  • Use HTTPS only
  • Implement proper logging
  • Use API versioning

Testing

Unit Testing

  • Write tests for all business logic
  • Use Jest and React Testing Library
  • Mock external dependencies
  • Test edge cases
  • Maintain high test coverage
  • Use proper test organization
  • Implement proper test naming

Integration Testing

  • Test component interactions
  • Test API integrations
  • Test database operations
  • Use proper test data
  • Implement proper cleanup
  • Test error scenarios
  • Use proper test isolation

E2E Testing

  • Use Cypress or Playwright
  • Test critical user flows
  • Implement proper test data
  • Test across different browsers
  • Test responsive design
  • Implement proper test reporting
  • Use proper test organization

Documentation

Code Documentation

  • Use JSDoc for function documentation
  • Document complex algorithms
  • Document API endpoints
  • Document component props
  • Document state management
  • Document error handling
  • Document testing strategy

API Documentation

  • Use OpenAPI/Swagger
  • Document all endpoints
  • Document request/response formats
  • Document error codes
  • Document authentication
  • Document rate limits
  • Document versioning

Project Documentation

  • Maintain up-to-date README
  • Document setup instructions
  • Document deployment process
  • Document architecture decisions
  • Document coding standards
  • Document testing strategy
  • Document security measures

Deployment & DevOps

CI/CD

  • Use GitHub Actions or similar
  • Implement automated testing
  • Implement automated deployment
  • Use proper environment management
  • Implement proper versioning
  • Use proper artifact management
  • Implement proper rollback strategy

Monitoring

  • Use proper logging
  • Implement error tracking
  • Monitor performance metrics
  • Monitor security events
  • Implement proper alerting
  • Use proper dashboards
  • Implement proper reporting

Infrastructure

  • Use Infrastructure as Code
  • Implement proper scaling
  • Use proper backup strategy
  • Implement proper disaster recovery
  • Use proper security measures
  • Implement proper monitoring
  • Use proper documentation

Accessibility

ARIA Best Practices

// Example of accessible component with ARIA attributes
function AccessibleButton() {
  return (
    <button
      aria-label="Close dialog"
      aria-expanded="false"
      aria-controls="dialog-content"
      className="rounded-md bg-blue-500 px-4 py-2 text-white"
    >
      <span className="sr-only">Close</span>
      <XIcon className="h-4 w-4" />
    </button>
  )
}

Keyboard Navigation

// Example of keyboard-accessible component
function AccessibleDropdown() {
  const [isOpen, setIsOpen] = useState(false)
  
  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === 'Escape') {
      setIsOpen(false)
    }
  }
  
  return (
    <div
      role="combobox"
      aria-expanded={isOpen}
      aria-haspopup="listbox"
      onKeyDown={handleKeyDown}
    >
      <button
        onClick={() => setIsOpen(!isOpen)}
        aria-controls="dropdown-list"
      >
        Select option
      </button>
      {isOpen && (
        <ul
          id="dropdown-list"
          role="listbox"
          tabIndex={-1}
        >
          <li role="option">Option 1</li>
          <li role="option">Option 2</li>
        </ul>
      )}
    </div>
  )
}

Screen Reader Support

// Example of screen reader friendly component
function AccessibleForm() {
  return (
    <form aria-labelledby="form-title">
      <h2 id="form-title">Contact Form</h2>
      
      <div>
        <label htmlFor="name">Name</label>
        <input
          id="name"
          type="text"
          aria-required="true"
          aria-invalid={false}
        />
      </div>
      
      <div>
        <label htmlFor="email">Email</label>
        <input
          id="email"
          type="email"
          aria-required="true"
          aria-invalid={false}
        />
      </div>
      
      <button type="submit">Submit</button>
    </form>
  )
}

Internationalization

Setup with next-intl

// Example of i18n setup with next-intl
import { useTranslations } from 'next-intl'

function InternationalizedComponent() {
  const t = useTranslations('Common')
  
  return (
    <div>
      <h1>{t('welcome')}</h1>
      <p>{t('description')}</p>
      <button>{t('actions.submit')}</button>
    </div>
  )
}

Date and Number Formatting

// Example of localized formatting
import { useFormatter } from 'next-intl'

function FormattedContent() {
  const format = useFormatter()
  
  return (
    <div>
      <p>
        {format.dateTime(new Date(), {
          year: 'numeric',
          month: 'long',
          day: 'numeric'
        })}
      </p>
      <p>
        {format.number(1234.56, {
          style: 'currency',
          currency: 'USD'
        })}
      </p>
    </div>
  )
}

RTL Support

// Example of RTL-aware component
function RTLComponent() {
  return (
    <div dir="auto" className="text-right">
      <p>This text will automatically align based on the content language</p>
      <div className="flex flex-row-reverse">
        <button>Button 1</button>
        <button>Button 2</button>
      </div>
    </div>
  )
}

Language Detection

// Example of language detection and switching
import { useRouter } from 'next/navigation'
import { useLocale } from 'next-intl'

function LanguageSwitcher() {
  const router = useRouter()
  const locale = useLocale()
  
  const switchLanguage = (newLocale: string) => {
    router.push(`/${newLocale}`)
  }
  
  return (
    <div>
      <button
        onClick={() => switchLanguage('en')}
        className={locale === 'en' ? 'font-bold' : ''}
      >
        English
      </button>
      <button
        onClick={() => switchLanguage('es')}
        className={locale === 'es' ? 'font-bold' : ''}
      >
        Español
      </button>
    </div>
  )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment