> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# SSG Helper

> Static Site Generation helper for pre-rendering pages

<Warning>
  Parts of the SSG Helper are experimental. The API may change in future versions.
</Warning>

The SSG (Static Site Generation) Helper enables pre-rendering of Hono applications to static files, allowing you to generate static HTML, CSS, JSON, and other assets at build time.

## Import

```typescript theme={null}
import { toSSG, fetchRoutesContent, saveContentToFile } from 'hono/ssg'
import { ssgParams, isSSGContext, disableSSG, onlySSG } from 'hono/ssg'
import type { ToSSGOptions, ToSSGResult } from 'hono/ssg'
```

## Functions

### toSSG()

Generates static files from a Hono application.

```typescript theme={null}
function toSSG(
  app: Hono<any, any, any>,
  fsModule: FileSystemModule,
  options?: ToSSGOptions
): Promise<ToSSGResult>
```

<ParamField path="app" type="Hono" required>
  The Hono application instance to generate static files from
</ParamField>

<ParamField path="fsModule" type="FileSystemModule" required>
  File system module with `writeFile` and `mkdir` methods (e.g., Node.js `fs/promises`)
</ParamField>

<ParamField path="options" type="ToSSGOptions">
  Configuration options for static generation
</ParamField>

<ResponseField name="return" type="Promise<ToSSGResult>">
  Result object containing:

  * `success`: boolean indicating if generation succeeded
  * `files`: array of generated file paths
  * `error`: Error object if generation failed
</ResponseField>

**Example**

```typescript theme={null}
import { Hono } from 'hono'
import { toSSG } from 'hono/ssg'
import fs from 'fs/promises'

const app = new Hono()

app.get('/', (c) => c.html('<h1>Home</h1>'))
app.get('/about', (c) => c.html('<h1>About</h1>'))
app.get('/api/data', (c) => c.json({ message: 'Hello' }))

// Generate static files
const result = await toSSG(app, fs, {
  dir: './dist'
})

if (result.success) {
  console.log(`Generated ${result.files.length} files`)
  result.files.forEach(file => console.log(file))
} else {
  console.error('Generation failed:', result.error)
}
```

### ssgParams()

Middleware to define parameters for dynamic routes during SSG.

```typescript theme={null}
function ssgParams<E extends Env = Env>(
  params: SSGParams
): MiddlewareHandler<E>

function ssgParams<E extends Env = Env>(
  generateParams: (c: Context<E>) => SSGParams | Promise<SSGParams>
): MiddlewareHandler<E>
```

<ParamField path="params" type="SSGParams | Function" required>
  Either an array of parameter objects or a function that returns them
</ParamField>

<ResponseField name="return" type="MiddlewareHandler">
  Middleware that provides parameters for static generation
</ResponseField>

**Example**

```typescript theme={null}
import { ssgParams } from 'hono/ssg'

app.get(
  '/posts/:id',
  ssgParams(async (c) => {
    // Generate pages for these post IDs
    return [
      { id: '1' },
      { id: '2' },
      { id: '3' }
    ]
  }),
  (c) => {
    const id = c.req.param('id')
    return c.html(`<h1>Post ${id}</h1>`)
  }
)

// Static array
app.get(
  '/users/:userId',
  ssgParams([
    { userId: 'alice' },
    { userId: 'bob' }
  ]),
  (c) => {
    const userId = c.req.param('userId')
    return c.html(`<h1>User: ${userId}</h1>`)
  }
)
```

### isSSGContext()

Checks if the current request is running in SSG context.

```typescript theme={null}
function isSSGContext(c: Context): boolean
```

<ParamField path="c" type="Context" required>
  The Hono context object
</ParamField>

<ResponseField name="return" type="boolean">
  `true` if running in SSG context, `false` otherwise
</ResponseField>

**Example**

```typescript theme={null}
import { isSSGContext } from 'hono/ssg'

app.get('/page', (c) => {
  if (isSSGContext(c)) {
    // Render static version
    return c.html('<h1>Static Page</h1>')
  } else {
    // Render dynamic version with live data
    return c.html(`<h1>Dynamic Page - ${new Date()}</h1>`)
  }
})
```

### disableSSG()

Middleware to prevent a route from being statically generated.

```typescript theme={null}
function disableSSG(): MiddlewareHandler
```

<ResponseField name="return" type="MiddlewareHandler">
  Middleware that disables SSG for the route
</ResponseField>

**Example**

```typescript theme={null}
import { disableSSG } from 'hono/ssg'

// This route will not be statically generated
app.get('/admin', disableSSG(), (c) => {
  return c.html('<h1>Admin Panel</h1>')
})

// Dynamic API route
app.get('/api/current-time', disableSSG(), (c) => {
  return c.json({ time: new Date().toISOString() })
})
```

### onlySSG()

Middleware to make a route only available during SSG (returns 404 at runtime).

```typescript theme={null}
function onlySSG(): MiddlewareHandler
```

<ResponseField name="return" type="MiddlewareHandler">
  Middleware that makes the route SSG-only
</ResponseField>

**Example**

```typescript theme={null}
import { onlySSG } from 'hono/ssg'

// This route only exists in static builds
app.get('/sitemap.xml', onlySSG(), (c) => {
  const sitemap = generateSitemap()
  return c.text(sitemap, 200, {
    'Content-Type': 'application/xml'
  })
})
```

### fetchRoutesContent()

Generator function that fetches content for all routes.

```typescript theme={null}
function* fetchRoutesContent<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'>(
  app: Hono<E, S, BasePath>,
  beforeRequestHook?: BeforeRequestHook,
  afterResponseHook?: AfterResponseHook,
  concurrency?: number
): Generator<Promise<...>>
```

<ParamField path="app" type="Hono" required>
  The Hono application instance
</ParamField>

<ParamField path="beforeRequestHook" type="BeforeRequestHook">
  Hook called before each request
</ParamField>

<ParamField path="afterResponseHook" type="AfterResponseHook">
  Hook called after each response
</ParamField>

<ParamField path="concurrency" type="number">
  Number of concurrent requests (default: 2)
</ParamField>

<ResponseField name="return" type="Generator">
  Generator yielding Promises that resolve to route content
</ResponseField>

### saveContentToFile()

Saves content to a file.

```typescript theme={null}
function saveContentToFile(
  data: Promise<{ routePath: string; content: string | ArrayBuffer; mimeType: string } | undefined>,
  fsModule: FileSystemModule,
  outDir: string,
  extensionMap?: Record<string, string>
): Promise<string | undefined>
```

<ParamField path="data" type="Promise<object>" required>
  Promise resolving to content data
</ParamField>

<ParamField path="fsModule" type="FileSystemModule" required>
  File system module
</ParamField>

<ParamField path="outDir" type="string" required>
  Output directory path
</ParamField>

<ParamField path="extensionMap" type="Record<string, string>">
  Custom MIME type to file extension mapping
</ParamField>

<ResponseField name="return" type="Promise<string | undefined>">
  Path to the saved file, or undefined if save was skipped
</ResponseField>

## Types

### ToSSGOptions

```typescript theme={null}
interface ToSSGOptions {
  dir?: string // Output directory (default: './static')
  concurrency?: number // Concurrent requests (default: 2)
  extensionMap?: Record<string, string> // MIME type to extension mapping
  plugins?: SSGPlugin[] // SSG plugins
}
```

### ToSSGResult

```typescript theme={null}
interface ToSSGResult {
  success: boolean
  files: string[]
  error?: Error
}
```

### SSGParams

```typescript theme={null}
type SSGParams = Array<Record<string, string>>

// Example:
const params: SSGParams = [
  { id: '1', slug: 'first' },
  { id: '2', slug: 'second' }
]
```

### FileSystemModule

```typescript theme={null}
interface FileSystemModule {
  writeFile(path: string, data: string | Uint8Array): Promise<void>
  mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}
```

## Advanced Usage

### Custom Extension Mapping

```typescript theme={null}
import { toSSG } from 'hono/ssg'
import fs from 'fs/promises'

const result = await toSSG(app, fs, {
  dir: './dist',
  extensionMap: {
    'text/html': 'html',
    'application/json': 'json',
    'text/xml': 'xml',
    'application/rss+xml': 'rss'
  }
})
```

### Build Script Example

```typescript theme={null}
// build.ts
import { Hono } from 'hono'
import { toSSG } from 'hono/ssg'
import fs from 'fs/promises'

const app = new Hono()

// Define your routes
app.get('/', (c) => c.html('<h1>Home</h1>'))
app.get('/about', (c) => c.html('<h1>About</h1>'))

// Generate static site
async function build() {
  console.log('Generating static site...')
  
  const result = await toSSG(app, fs, {
    dir: './dist',
    concurrency: 4
  })
  
  if (result.success) {
    console.log(`✓ Generated ${result.files.length} files`)
  } else {
    console.error('✗ Build failed:', result.error)
    process.exit(1)
  }
}

build()
```

### Dynamic Routes with Database

```typescript theme={null}
import { ssgParams } from 'hono/ssg'

app.get(
  '/blog/:slug',
  ssgParams(async () => {
    // Fetch all blog post slugs from database
    const posts = await db.posts.findAll()
    return posts.map(post => ({ slug: post.slug }))
  }),
  async (c) => {
    const slug = c.req.param('slug')
    const post = await db.posts.findBySlug(slug)
    
    return c.html(`
      <article>
        <h1>${post.title}</h1>
        <div>${post.content}</div>
      </article>
    `)
  }
)
```

## File Output

Generated files follow these patterns:

* `/` → `/index.html`
* `/about` → `/about.html`
* `/about/` → `/about/index.html`
* `/api/data` → `/api/data.json` (for JSON responses)
* `/feed.xml` → `/feed.xml`
