---
title: Static Site Generation (SSG) Overview | Guides
description: Learn how static site generation (SSG) works in Qwik Router.
contributors:
  - adamdbradley
  - AnthonyPAlicea
  - mhevery
  - ibousfiha
  - Kocal
  - eric-burel
  - julianobrasil
  - mrhoodz
  - hamatoyogi
updated_at: '2023-10-04T10:27:27Z'
created_at: '2023-03-20T23:45:13Z'
---

import PackageManagerTabs from '~/components/package-manager-tabs/index.tsx';

# Static Site Generation (SSG) Overview

Static Site Generation, or commonly referred to as "SSG", is the process of pre-rendering site webpages into static HTML files. The benefit is that when a visitor requests the webpage, the response is a pre-generated HTML file (a static file), and doesn't require the webpage's HTML to "rebuild" on the visitor's browser, or dynamically created by your server (more on this later).

Additionally, due to Qwik's underlying architecture, page performance also benefits by not requiring a Javascript "hydration" step, which can significantly lower performance and slow down user interactivity. By pre-rendering static `index.html` files with SSG, and combined with Qwik's [resumability](../../../(qwik)/concepts/resumable/index.mdx), static site generation offers many performance benefits over legacy solutions.

## SSG vs. Server-Side Rendered (SSR)

Qwik Router is capable of taking a Qwik application, no matter if it's a "webapp" or "website", and generate static HTML. Once it's generated as HTML, Qwik is fundamentally able to skip rebuilding the app by using [resumability](../../../(qwik)/concepts/resumable/index.mdx), since the app was already generated as HTML. Both Static Site Generation (SSG) and Server-Side Rendering (SSR) use the same process to generate the HTML. The main difference between the SSG and SSR however, is "when" the HTML is generated.

In a traditional setup, SSG pre-renders each webpage at build-time, while SSR render's each webpage on-demand for each HTTP request. SSG only needs to generate the HTML one time per build, which is great for webpages where multiple visitors should see the same content. In contrast, SSR is great when the webpage may be different for each visitor, and would need to render custom HTML for each individual HTTP request.

For example, SSG is ideal for a blog or docs site, where all the content should be the same for multiple visitors. While SSR may work fine for a blog, it may be an unnecessary strain for your HTTP servers to render the blog content for every visitor, even though they'd all end up seeing the same HTML.

However, an account dashboard would commonly have different content for each signed-in user. In this setup, each user should get their own rendered HTML with their account information, rather than everyone seeing the exact same content. This is where SSR would be preferred.

Ideally, the more you can do with static site generation the better, since that'll have less costs to your servers and faster response times.

With Qwik Router however, the decision to use SSG or SSR, does not have to be one or the other decision. Instead, your own implementation can choose to have some route paths use SSG, while some other pages use SSR. It's entirely up to you and your requirements.

## Static Site Generation Config

Static site generation is created from the built in adapter, to create an adapter run:


<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run qwik add static
```
</span>
<span q:slot="npm">
```shell
npm run qwik add static
```
</span>
<span q:slot="yarn">
```shell
yarn run qwik add static
```
</span>
<span q:slot="bun">
```shell
bun run qwik add static
```
</span>
</PackageManagerTabs>

Select `Adapter: Static site (.html files)`. Done!

### Changes

Running the above command will make the following changes to your project:

- A `build.server` script will be automatically added to your `package.json` file.
- A `adapters/ssg/vite.config.ts` file will be created.

Your build files will be generated into the `dist` folder.

You can build your static site using:

<PackageManagerTabs>
<span q:slot="pnpm">
```shell
pnpm run build.server
```
</span>
<span q:slot="npm">
```shell
npm run build.server
```
</span>
<span q:slot="yarn">
```shell
yarn run build.server
```
</span>
<span q:slot="bun">
```shell
bun run build.server
```
</span>
</PackageManagerTabs>

### SSG Config

The `adapters/ssg/vite.config.ts` file also includes the SSG config, which would be custom for each implementation.

#### `origin`

The URL `origin`, which is a combination of the scheme (protocol) and hostname (domain). For example, `https://qwik.dev` has the protocol `https://` and domain `qwik.dev`. However, the `origin` does _not_ include a `pathname`.

The `origin` is used to provide a full URL during Static Site Generation (SSG), and to simulate a complete URL rather than just the `pathname`. For example, in order to render a correct canonical tag URL or URLs within the `sitemap.xml`, the `origin` must be provided too.

If the site also starts with a pathname other than `/`, please use the `base` option in the Vite config options (the `basePathname` option in the Qwik Router config options is deprecated).

#### `outDir`

The `outDir` is a file system output directory where the static files should be written. In the example above, it's using Node's [fileURLToPath](https://nodejs.org/api/url.html#urlfileurltopathurl) to create an absolute file system path to write the static HTML files to.

#### Re-running SSG

SSG is designed to be run at build time, but it can also be re-run at any time after the initial build. This can be useful when you want to update the static HTML files without having to rebuild the entire application.

To re-run SSG, you can run the `server/run-ssg.js` script. This script will re-run the SSG process and update the static HTML files in the `dist` folder. (or whatever `outDir` you have configured in your SSG config).

## Dynamic SSG Routes

So far, we've only discussed how to generate static HTML files for a single route path. However, in most cases, you'll want to generate HTML files for multiple route paths that has dynamic params. For example, a product site may have a route path for each product, such as `/product/:id`. In this case, you'll want to generate HTML files for each product page, which would require generating HTML files for each product ID.

```tsx
import { component$ } from '@qwik.dev/core';
import { useLocation, type StaticGenerateHandler } from '@qwik.dev/router';
import { loadProductIds } from './load-product-ids';

export default component$(() => {
  const { params } = useLocation();

  return <p>Example: {params.id}</p>;
});

export const onStaticGenerate: StaticGenerateHandler = async ({ env }) => {
  // example of loading params for this use case
  // every implementation will be different
  const ids = await loadProductIds({
    apiKey: env.get('API_KEY'),
  });

  return {
    params: ids.map((id) => {
      return { id };
    }),
  };
};
```

In the above example, the `onStaticGenerate()` function is loading the product IDs from a `loadProductIds()` function by requesting an API behind an API key retrieved from an environment variable.
This function would be custom for each implementation, but the general idea is that you'll need to load the data for each product ID, and then generate HTML files for each product ID.

The `onStaticGenerate` function should be exported from the top-level of the module, and should return an object with a `params` property. The `params` property should be an array of objects, where each object is a set of params for the route path. For example, if the route path is `/product/:id`, then the `params` array should be an array of objects with an `id` property.

The directory structure for this example would be:

```bash
src/
└── routes/
    └── product/
        └── [id]/
            └── index.tsx
```

Notice that the `index.tsx` file is inside a directory named `[id]`. This is a special directory name that tells Qwik Router to generate HTML files for each `id` param. The `index.tsx` file is the default file that Qwik Router will use when generating HTML files for a route path.
