Why SSR is Better Than SSG

2 min read

Why SSR Alone is Sufficient

SSR (server-side rendering) refers to rendering pages on-demand at runtime on the server, then sending them to the frontend. SSG (server-side generation) refers to pre-compiling HTML and other static files, and directly sending these static files to the frontend when users request them.

With these definitions clear, it's easy to understand that SSR can embed dynamic logic but requires a constantly running server, while SSG is more suitable for static content that can be placed on a CDN. The well-known NextJS framework supports both SSR and SSG. However, the newer Remix framework has completely abandoned SSG, believing there are enough benefits to this approach. Based on my experience, with modern CDN support, this approach does make sense.

  • Modern CDNs like Cloudflare and Vercel support serverless environments, making deploying NodeJS applications almost as convenient as deploying static files.
  • The main advantage of SSG is deploying static files directly to CDNs to save server resources. However, SSR can also easily cache content on CDNs by setting appropriate Cache-Control headers. This means the SSR server only runs on the first request, making it almost indistinguishable from static files.
  • No need to recompile and redeploy every time static content is modified.
  • Once you abandon the NextJS approach of distinguishing between SSG and SSR, the mental burden is significantly reduced. Cache settings rely entirely on HTML standards like Cache-Control, without needing to learn an additional set of interfaces. Debugging cache issues also becomes much easier - when the browser caches a request that shouldn't be cached, you only need to look at your Response configuration.

An Example

In fact, Remix's official website is an excellent example. Their documentation is generated using SSR. Many people might think that since documentation is just static text, wouldn't SSG be best? The Remix team explains their reasoning.

Their documentation is stored in Remix's source code repository, not directly written in the official website. This approach of keeping documentation with source code has several benefits:

  • More referential when reading code
  • Easier to modify documentation when changing code
  • Git automatically tracks documentation changes, binding them to source code versions

The official website's server reads from Remix's source code repository and generates documentation pages through SSR. This approach has several advantages:

  • No need to recompile and redeploy the entire website every time documentation is modified
  • Can directly access documentation for any version of Remix from the source code repository, even the latest documentation from the dev branch. This allows the official website to display documentation corresponding to any Remix version.

Since documentation isn't real-time data, they've implemented some cache optimizations:

  • Using lru-cache to cache documentation results. The cache is on the server side, so all clients benefit.
    • Timeout set to 5 minutes
  • Setting Cache-Control to stale-while-revalidate. This allows CDN caching:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    return json(
      { doc },
      {
        headers: {
          "Cache-Control": "max-age=300, stale-while-revalidate=604800",
        },
      }
    );
    
    This means that when documentation is modified, the official website will display the changes with a maximum delay of 5 minutes (max-age=300).