Skip to main content

    SSR

    SSR returns fully rendered HTML on each request, helping bots and users see content faster and improving indexability and first paint.

    Definition

    SSR (Server-Side Rendering) renders your framework output (e.g., React) into HTML on the server per request. It makes content and metadata/structured data available immediately, which is very friendly to JavaScript SEO.

    Why it matters

    • Ships indexable content immediately without waiting for JavaScript execution
    • More stable first paint: content arrives first, interactions follow after hydration — improves LCP
    • Ideal for real-time or personalized pages like user dashboards
    • Social sharing works correctly: OG tags are in initial HTML for Facebook/Twitter crawlers
    • Supports AI engine indexing: ChatGPT/Perplexity crawlers have limited rendering capabilities
    • Reduces dependence on Googlebot's render queue: page is immediately readable
    • Consistent SEO experience: both users and bots see the same content

    How to implement

    • Ensure SSR output includes complete head: title/description/canonical/hreflang/schema
    • Avoid hydration mismatch: keep initial HTML consistent with CSR output or React will throw errors
    • Use SSG/prerender for static pages to reduce SSR server costs
    • Set caching strategy: use stale-while-revalidate for identical requests to reduce renders
    • Monitor TTFB: SSR adds server processing time — optimize data fetching
    • Handle errors properly: ensure 404/500 pages are also SSR'd with correct status codes
    • Use streaming SSR: React 18+ supports progressive HTML delivery for better first paint

    Examples

    typescript
    // pages/product/[id].tsx
    import { GetServerSideProps } from 'next';
    import Head from 'next/head';
    
    interface ProductProps {
      product: { id: string; name: string; price: number };
    }
    
    export default function ProductPage({ product }: ProductProps) {
      return (
        <>
          <Head>
            <title>{product.name} | My Store</title>
            <meta name="description" content={`Buy ${product.name} for ${product.price}`} />
            <link rel="canonical" href={`https://mystore.com/product/${product.id}`} />
          </Head>
          <h1>{product.name}</h1>
          <p>Price: ${product.price}</p>
        </>
      );
    }
    
    export const getServerSideProps: GetServerSideProps = async ({ params, res }) => {
      const product = await fetchProduct(params?.id as string);
      if (!product) {
        return { notFound: true }; // Returns 404
      }
      // Set caching (CDN-friendly)
      res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');
      return { props: { product } };
    };
    typescript
    // app/routes/blog.$slug.tsx
    import { json, LoaderFunctionArgs, MetaFunction } from '@remix-run/node';
    import { useLoaderData } from '@remix-run/react';
    
    export const loader = async ({ params }: LoaderFunctionArgs) => {
      const post = await getPost(params.slug!);
      if (!post) {
        throw new Response('Not Found', { status: 404 });
      }
      return json(post, {
        headers: { 'Cache-Control': 's-maxage=3600' }
      });
    };
    
    export const meta: MetaFunction<typeof loader> = ({ data }) => {
      if (!data) return [{ title: 'Not Found' }];
      return [
        { title: data.title },
        { name: 'description', content: data.excerpt },
        { property: 'og:title', content: data.title },
      ];
    };
    
    export default function BlogPost() {
      const post = useLoaderData<typeof loader>();
      return <article><h1>{post.title}</h1><div>{post.content}</div></article>;
    }

    Related

    FAQ

    Common questions about this term.

    Back to glossary