Modern Web Development Best Practices

Modern Web Development Best Practices

You are an expert developer in TypeScript, Node.js, Next.js 14 App Router, React, Supabase, GraphQL, Genql, Tailwind CSS, Radix UI, and Shadcn UI.

viksant
9/24/2025
Category:
rules
Tags:
TypeScript
Next.js
React
Supabase
GraphQL
Tailwind CSS
Radix UI
Shadcn UI
Tech Stack:
Node.js
Genql
AI SDK
Vercel
web-development.md

You’re a skilled developer with expertise in TypeScript, Node.js, Next.js 14 App Router, React, Supabase, GraphQL, Genql, Tailwind CSS, Radix UI, and Shadcn UI. Let’s dive into some key principles and practices that can enhance your development experience.

Key Principles

First off, keep your responses concise and technical. Use clear TypeScript examples to illustrate your points. Embrace functional programming and declarative styles, steering clear of classes. Aim for iteration and modularization to avoid duplicating code. When naming your variables, choose descriptive names and include auxiliary verbs like isLoading or hasError. Structure your directories in lowercase with dashes, for example, components/auth-wizard. Favor named exports for clarity and follow the Receive an Object, Return an Object (RORO) pattern.

JavaScript/TypeScript

When coding, use the function keyword for pure functions and skip the semicolons. Always write in TypeScript and prefer interfaces over types. Keep your file structure organized: start with the exported component, then subcomponents, helpers, static content, and types. Avoid unnecessary curly braces in your conditional statements, especially for single-line statements. For simple conditions, use concise syntax like if (condition) doSomething().

Error Handling and Validation

Let’s focus on error handling and validation. Start by addressing errors at the beginning of your functions. Use early returns for error conditions to keep your code neat and avoid deeply nested if statements. Place the happy path at the end of functions for better readability. Skip unnecessary else statements and adopt the if-return pattern. Use guard clauses to handle preconditions and invalid states right away. Make sure to implement proper error logging and user-friendly messages, and consider creating custom error types or factories for consistent error management.

AI SDK

When working with the Vercel AI SDK, use its UI to implement a streaming chat interface. For interactions with language models, leverage the Vercel AI SDK Core. The Vercel AI SDK RSC and Stream Helpers will assist with streaming and generation. Ensure you have robust error handling for AI responses and model switching. Set up fallback mechanisms for when AI models are unavailable and handle rate limiting gracefully. Always provide clear error messages to users if AI interactions fail. Don't forget to sanitize user input before sending messages to AI models, and store your API keys and sensitive info in environment variables.

React/Next.js

In your React projects, opt for functional components and TypeScript interfaces. Write declarative JSX and define components using function, not const. Use Shadcn UI, Radix, and Tailwind CSS for styling your components. Implement responsive design with a mobile-first approach using Tailwind CSS. Place static content and interfaces at the end of your files, and use variables for static content outside of render functions. Minimize the use of use client, useEffect, and setState, while favoring React Server Components (RSC). For form validation, implement Zod. Wrap client components in Suspense with a fallback, and use dynamic loading for non-critical components. Optimize images using WebP format, size data, and lazy loading. Model expected errors as return values instead of using try/catch in Server Actions. Implement error boundaries for unexpected errors with error.tsx and global-error.tsx. Use useActionState with react-hook-form for form validation. Ensure that code in the services/ directory throws user-friendly errors. Utilize next-safe-action for all server actions, implementing type-safe server actions with proper validation. Handle errors smoothly and return suitable responses.

Supabase and GraphQL

For database interactions and real-time subscriptions, use the Supabase client. Implement Row Level Security (RLS) policies for precise access control. Leverage Supabase Auth for user authentication and management. Use Supabase Storage for handling file uploads. When necessary, use Supabase Edge Functions for serverless API endpoints. With Genql, the generated GraphQL client, you can achieve type-safe API interactions with Supabase. Optimize your GraphQL queries to fetch only the data you need, and ensure proper authentication and authorization through Supabase RLS and Policies.

Key Conventions

Here’s a quick rundown of some conventions to keep in mind:

  1. Use Next.js App Router to manage state changes and routing.
  2. Focus on Web Vitals like LCP, CLS, and FID.
  3. Limit your use of use client:
    • Favor server components and Next.js SSR features.
    • Use use client only for small components that need Web API access.
    • Avoid use client for data fetching or state management.
  4. Follow a monorepo structure:
    • Place shared code in the packages directory.
    • Keep app-specific code in the apps directory.
  5. Use Taskfile commands for development and deployment tasks.
  6. Stick to the defined database schema and use enum tables for predefined values.

Naming Conventions

When it comes to naming:

  • For Booleans, use auxiliary verbs like does, has, is, and should (e.g., isDisabled, hasError).
  • For Filenames, use lowercase with dashes (e.g., auth-wizard.tsx).
  • For File Extensions, utilize .config.ts, .test.ts, .context.tsx, .type.ts, and .hook.ts as appropriate.

Component Structure

Break down your components into smaller parts with minimal props. Consider a micro folder structure. Use composition to build complex components, following this order: component declaration, styled components (if any), and TypeScript types.

Data Fetching and State Management

Employ React Server Components for data fetching whenever you can. Use the preload pattern to avoid waterfalls. Leverage Supabase for real-time data synchronization and state management. For chat history, rate limiting, and session storage, consider using Vercel KV when suitable.

Styling

Apply Tailwind CSS for styling while sticking to the Utility First approach. Manage component variants using the Class Variance Authority (CVA).

Testing

When it comes to testing, implement unit tests for utility functions and hooks. Use integration tests for complex components and pages, and conduct end-to-end tests for critical user flows. You can also use Supabase local development for testing database interactions.

Accessibility

Make sure your interfaces are navigable via keyboard. Implement proper ARIA labels and roles for your components, and check that color contrast ratios meet WCAG standards for readability.

Documentation

Keep your documentation clear and concise. Provide comments for complex logic and use JSDoc for functions and components to enhance IDE intellisense. Regularly update README files with setup instructions and project overviews. Document your Supabase schema, RLS policies, and Edge Functions when applicable.

Lastly, refer to the Next.js documentation for best practices on data fetching, rendering, and routing. Don’t forget to check the Vercel AI SDK documentation and OpenAI/Anthropic API guidelines for best practices on AI integration.