Matter AI | Code Reviewer Documentation home pagelight logodark logo
  • Contact
  • Github
  • Sign in
  • Sign in
Documentation
Changelog
  • Blog
  • Discord
  • Github
  • Introduction
    • What is Matter AI?
    Getting Started
    • QuickStart
    Features
    • Security Analysis
    • Code Quality
    • Similarity Search
    • Agentic Chat
    • RuleSets
    • Memories
    • Analytics
    • Command List
    • Configurations
    Patterns
    • Languages
      • Supported Languages
      • Python
      • Java
      • JavaScript
      • TypeScript
      • Node.js
      • React
      • Fastify
      • Next.js
      • Terraform
      • C#
      • C++
      • C
      • Go
      • Rust
      • Swift
      • React Native
      • Spring Boot
      • Kotlin
      • Flutter
      • Ruby
      • PHP
      • Scala
      • Perl
      • R
      • Dart
      • Elixir
      • Erlang
      • Haskell
      • Lua
      • Julia
      • Clojure
      • Groovy
      • Fortran
      • COBOL
      • Pascal
      • Assembly
      • Bash
      • PowerShell
      • SQL
      • PL/SQL
      • T-SQL
      • MATLAB
      • Objective-C
      • VBA
      • ABAP
      • Apex
      • Apache Camel
      • Crystal
      • D
      • Delphi
      • Elm
      • F#
      • Hack
      • Lisp
      • OCaml
      • Prolog
      • Racket
      • Scheme
      • Solidity
      • Verilog
      • VHDL
      • Zig
      • MongoDB
      • ClickHouse
      • MySQL
      • GraphQL
      • Redis
      • Cassandra
      • Elasticsearch
    • Security
    • Performance
    Integrations
    • Code Repositories
    • Team Messengers
    • Ticketing
    Enterprise
    • Enterprise Deployment Overview
    • Enterprise Configurations
    • Observability and Fallbacks
    • Create Your Own GitHub App
    • Self-Hosting Options
    • RBAC
    Patterns
    Languages

    Next.js

    Next.js is a React framework that enables server-side rendering, static site generation, and other advanced features with zero configuration. It provides a powerful foundation for building production-ready React applications.

    Next.js Anti-Patterns Overview

    Next.js, despite its powerful features and optimizations, has several common anti-patterns that can lead to performance issues, maintenance problems, and poor user experience. Here are the most important anti-patterns to avoid when building Next.js applications.

    Not Using the Correct Data Fetching Method

    Copy
    // Anti-pattern: Using client-side data fetching for static content
    function ProductPage({ productId }) {
      const [product, setProduct] = useState(null);
      const [loading, setLoading] = useState(true);
      
      useEffect(() => {
        async function fetchProduct() {
          const res = await fetch(`/api/products/${productId}`);
          const data = await res.json();
          setProduct(data);
          setLoading(false);
        }
        
        fetchProduct();
      }, [productId]);
      
      if (loading) return <div>Loading...</div>;
      
      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
        </div>
      );
    }
    
    // Better approach: Use getStaticProps for static content
    export async function getStaticProps({ params }) {
      const res = await fetch(`https://api.example.com/products/${params.id}`);
      const product = await res.json();
      
      return {
        props: {
          product,
        },
        revalidate: 60, // Optional: Regenerate page after 60 seconds
      };
    }
    
    export async function getStaticPaths() {
      const res = await fetch('https://api.example.com/products');
      const products = await res.json();
      
      const paths = products.map((product) => ({
        params: { id: product.id.toString() },
      }));
      
      return { paths, fallback: 'blocking' };
    }
    
    function ProductPage({ product }) {
      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
        </div>
      );
    }
    

    Using client-side data fetching for content that could be pre-rendered leads to poor performance and SEO. Choose the appropriate data fetching method: getStaticProps for static content, getServerSideProps for dynamic content, and client-side fetching only for user-specific or frequently changing data.

    Not Using Image Optimization

    Copy
    // Anti-pattern: Using regular img tags
    function ProductCard({ product }) {
      return (
        <div className="card">
          <img 
            src={product.imageUrl} 
            alt={product.name} 
            width={300} 
            height={200} 
          />
          <h3>{product.name}</h3>
        </div>
      );
    }
    
    // Better approach: Use Next.js Image component
    import Image from 'next/image';
    
    function ProductCard({ product }) {
      return (
        <div className="card">
          <Image 
            src={product.imageUrl} 
            alt={product.name} 
            width={300} 
            height={200} 
            placeholder="blur"
            blurDataURL="data:image/jpeg;base64,..."
            priority={product.featured}
          />
          <h3>{product.name}</h3>
        </div>
      );
    }
    

    Regular <img> tags don’t benefit from Next.js’s automatic image optimization. Use the next/image component to get automatic image optimization, lazy loading, and proper sizing.

    Not Using Next.js Link Component

    Copy
    // Anti-pattern: Using regular anchor tags
    function Navigation() {
      return (
        <nav>
          <a href="/">Home</a>
          <a href="/about">About</a>
          <a href="/products">Products</a>
        </nav>
      );
    }
    
    // Better approach: Use Next.js Link component
    import Link from 'next/link';
    
    function Navigation() {
      return (
        <nav>
          <Link href="/">
            <a>Home</a>
          </Link>
          <Link href="/about">
            <a>About</a>
          </Link>
          <Link href="/products">
            <a>Products</a>
          </Link>
        </nav>
      );
    }
    
    // In Next.js 13+ with the App Router
    import Link from 'next/link';
    
    function Navigation() {
      return (
        <nav>
          <Link href="/">Home</Link>
          <Link href="/about">About</Link>
          <Link href="/products">Products</Link>
        </nav>
      );
    }
    

    Regular anchor tags cause full page reloads. Use the next/link component for client-side navigation between pages, which is faster and preserves state.

    Misusing the API Routes

    Copy
    // Anti-pattern: Using API routes to fetch data for getStaticProps
    // pages/products/[id].js
    export async function getStaticProps({ params }) {
      // Don't do this - it creates an unnecessary network request
      const res = await fetch(`http://localhost:3000/api/products/${params.id}`);
      const product = await res.json();
      
      return {
        props: { product },
      };
    }
    
    // pages/api/products/[id].js
    export default async function handler(req, res) {
      const { id } = req.query;
      const product = await getProductFromDatabase(id);
      res.status(200).json(product);
    }
    
    // Better approach: Import the data fetching logic directly
    // lib/products.js
    export async function getProductById(id) {
      return await getProductFromDatabase(id);
    }
    
    // pages/products/[id].js
    import { getProductById } from '../../lib/products';
    
    export async function getStaticProps({ params }) {
      const product = await getProductById(params.id);
      
      return {
        props: { product },
      };
    }
    
    // pages/api/products/[id].js
    import { getProductById } from '../../../lib/products';
    
    export default async function handler(req, res) {
      const { id } = req.query;
      const product = await getProductById(id);
      res.status(200).json(product);
    }
    

    Using API routes to fetch data for getStaticProps or getServerSideProps creates unnecessary network requests. Import the data fetching logic directly in both server-side functions and API routes.

    Not Using Incremental Static Regeneration

    Copy
    // Anti-pattern: Using getServerSideProps for semi-static content
    export async function getServerSideProps() {
      const res = await fetch('https://api.example.com/products');
      const products = await res.json();
      
      return {
        props: { products },
      };
    }
    
    // Better approach: Use Incremental Static Regeneration
    export async function getStaticProps() {
      const res = await fetch('https://api.example.com/products');
      const products = await res.json();
      
      return {
        props: { products },
        revalidate: 60, // Regenerate page after 60 seconds if requested
      };
    }
    

    Using getServerSideProps for content that doesn’t change frequently adds unnecessary server load. Use Incremental Static Regeneration (ISR) with revalidate for content that changes occasionally.

    Not Optimizing for Core Web Vitals

    Copy
    // Anti-pattern: Loading large JavaScript libraries upfront
    import LargeChart from 'heavy-chart-library';
    
    function DashboardPage() {
      return (
        <div>
          <h1>Dashboard</h1>
          <LargeChart data={someData} />
        </div>
      );
    }
    
    // Better approach: Use dynamic imports and suspense
    import dynamic from 'next/dynamic';
    import { Suspense } from 'react';
    
    const LargeChart = dynamic(() => import('heavy-chart-library'), {
      loading: () => <div>Loading chart...</div>,
      ssr: false, // Disable server-side rendering if the library isn't SSR compatible
    });
    
    function DashboardPage() {
      return (
        <div>
          <h1>Dashboard</h1>
          <Suspense fallback={<div>Loading chart...</div>}>
            <LargeChart data={someData} />
          </Suspense>
        </div>
      );
    }
    

    Loading large JavaScript libraries upfront hurts performance metrics like Largest Contentful Paint (LCP) and Time to Interactive (TTI). Use dynamic imports, code splitting, and prioritize loading critical content first.

    Not Using TypeScript

    Copy
    // Anti-pattern: Using plain JavaScript without type checking
    function UserProfile({ user }) {
      return (
        <div>
          <h1>{user.name}</h1>
          <p>{user.email}</p>
          <p>{user.address.street}, {user.address.city}</p>
        </div>
      );
    }
    
    // Better approach: Use TypeScript
    interface Address {
      street: string;
      city: string;
      zipCode: string;
      country: string;
    }
    
    interface User {
      id: string;
      name: string;
      email: string;
      address: Address;
    }
    
    interface UserProfileProps {
      user: User;
    }
    
    function UserProfile({ user }: UserProfileProps) {
      return (
        <div>
          <h1>{user.name}</h1>
          <p>{user.email}</p>
          <p>{user.address.street}, {user.address.city}</p>
        </div>
      );
    }
    

    Not using TypeScript can lead to runtime errors and makes refactoring more difficult. Use TypeScript to catch errors at compile time and improve code maintainability.

    Not Using Layout Components

    Copy
    // Anti-pattern: Duplicating layout code in every page
    function HomePage() {
      return (
        <div>
          <header>
            <nav>{/* Navigation items */}</nav>
          </header>
          <main>
            <h1>Welcome to our site</h1>
            {/* Page content */}
          </main>
          <footer>
            {/* Footer content */}
          </footer>
        </div>
      );
    }
    
    function AboutPage() {
      return (
        <div>
          <header>
            <nav>{/* Navigation items */}</nav>
          </header>
          <main>
            <h1>About Us</h1>
            {/* Page content */}
          </main>
          <footer>
            {/* Footer content */}
          </footer>
        </div>
      );
    }
    
    // Better approach: Use layout components
    function MainLayout({ children }) {
      return (
        <div>
          <header>
            <nav>{/* Navigation items */}</nav>
          </header>
          <main>{children}</main>
          <footer>
            {/* Footer content */}
          </footer>
        </div>
      );
    }
    
    function HomePage() {
      return (
        <MainLayout>
          <h1>Welcome to our site</h1>
          {/* Page content */}
        </MainLayout>
      );
    }
    
    function AboutPage() {
      return (
        <MainLayout>
          <h1>About Us</h1>
          {/* Page content */}
        </MainLayout>
      );
    }
    
    // In Next.js 13+ with App Router
    // app/layout.js
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body>
            <header>
              <nav>{/* Navigation items */}</nav>
            </header>
            <main>{children}</main>
            <footer>
              {/* Footer content */}
            </footer>
          </body>
        </html>
      );
    }
    

    Duplicating layout code across pages leads to maintenance issues. Use layout components or the App Router’s layout system to share common UI elements across pages.

    Not Using Next.js Config Properly

    Copy
    // Anti-pattern: Not configuring Next.js properly
    // next.config.js
    module.exports = {
      // No configuration
    };
    
    // Better approach: Configure Next.js properly
    // next.config.js
    module.exports = {
      images: {
        domains: ['images.example.com'], // Allow images from this domain
        formats: ['image/avif', 'image/webp'], // Specify image formats
      },
      i18n: {
        locales: ['en', 'fr', 'es'],
        defaultLocale: 'en',
      },
      async redirects() {
        return [
          {
            source: '/old-blog/:slug',
            destination: '/blog/:slug',
            permanent: true,
          },
        ];
      },
      async headers() {
        return [
          {
            source: '/:path*',
            headers: [
              {
                key: 'X-Content-Type-Options',
                value: 'nosniff',
              },
              {
                key: 'X-Frame-Options',
                value: 'DENY',
              },
            ],
          },
        ];
      },
    };
    

    Not configuring Next.js properly means missing out on important optimizations and features. Use the Next.js config file to configure image domains, internationalization, redirects, headers, and other important settings.

    Not Using Error Boundaries

    Copy
    // Anti-pattern: No error handling
    function ProductPage({ product }) {
      return (
        <div>
          <Header />
          <ProductDetails product={product} /> {/* If this crashes, the whole page crashes */}
          <RelatedProducts ids={product.relatedIds} />
          <Footer />
        </div>
      );
    }
    
    // Better approach: Use error boundaries
    import { ErrorBoundary } from 'react-error-boundary';
    
    function ErrorFallback({ error, resetErrorBoundary }) {
      return (
        <div role="alert">
          <p>Something went wrong:</p>
          <pre>{error.message}</pre>
          <button onClick={resetErrorBoundary}>Try again</button>
        </div>
      );
    }
    
    function ProductPage({ product }) {
      return (
        <div>
          <Header />
          <ErrorBoundary 
            FallbackComponent={ErrorFallback}
            onReset={() => {
              // Reset the state of your app here
            }}
          >
            <ProductDetails product={product} />
          </ErrorBoundary>
          <RelatedProducts ids={product.relatedIds} />
          <Footer />
        </div>
      );
    }
    

    Without error boundaries, a runtime error in a component can break the entire page. Use error boundaries to gracefully handle errors and display fallback UIs.

    Not Using Server Components Properly

    Copy
    // Anti-pattern: Using client components for everything in Next.js 13+
    'use client';
    
    import { useState } from 'react';
    
    async function getData() {
      const res = await fetch('https://api.example.com/data');
      return res.json();
    }
    
    export default function Page() {
      const [count, setCount] = useState(0);
      const data = await getData(); // This will error in client components
      
      return (
        <div>
          <h1>Data: {data.title}</h1>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    
    // Better approach: Split into server and client components
    // Page.js (Server Component)
    import { Counter } from './Counter';
    
    async function getData() {
      const res = await fetch('https://api.example.com/data');
      return res.json();
    }
    
    export default async function Page() {
      const data = await getData();
      
      return (
        <div>
          <h1>Data: {data.title}</h1>
          <Counter />
        </div>
      );
    }
    
    // Counter.js (Client Component)
    'use client';
    
    import { useState } from 'react';
    
    export function Counter() {
      const [count, setCount] = useState(0);
      
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    

    Using client components for everything in Next.js 13+ misses the benefits of server components. Use server components for data fetching and rendering static content, and client components only for interactive parts of your UI.

    Not Using Proper Caching Strategies

    Copy
    // Anti-pattern: Not implementing proper caching
    // pages/products/[id].js
    export async function getServerSideProps({ params }) {
      const res = await fetch(`https://api.example.com/products/${params.id}`);
      const product = await res.json();
      
      return {
        props: { product },
      };
    }
    
    // Better approach: Implement proper caching
    // pages/products/[id].js
    export async function getStaticProps({ params }) {
      const res = await fetch(`https://api.example.com/products/${params.id}`, {
        headers: {
          'Cache-Control': 'public, s-maxage=10, stale-while-revalidate=59',
        },
      });
      const product = await res.json();
      
      return {
        props: { product },
        revalidate: 60,
      };
    }
    
    // In Next.js 13+ App Router
    // app/products/[id]/page.js
    export const revalidate = 60; // Revalidate at most every 60 seconds
    
    async function getProduct(id) {
      const res = await fetch(`https://api.example.com/products/${id}`, {
        next: { revalidate: 60 },
      });
      return res.json();
    }
    
    export default async function ProductPage({ params }) {
      const product = await getProduct(params.id);
      
      return (
        <div>
          <h1>{product.name}</h1>
          <p>{product.description}</p>
        </div>
      );
    }
    

    Not implementing proper caching strategies can lead to unnecessary API calls and slower performance. Use appropriate caching headers and Next.js’s built-in caching mechanisms like ISR and the fetch API’s cache options.

    FastifyTerraform
    websitexgithublinkedin
    Powered by Mintlify
    Assistant
    Responses are generated using AI and may contain mistakes.