Last updated June 23, 2026

Deployment

1 minute read

folio.md produces plain HTML, CSS, and JS in dist/, ready to serve from GitHub Pages or GitLab Pages.

Build

If you installed folio as a dependency via folio init:

bash
bun run folio:build    # bun
npm run folio:build    # npm
yarn folio:build       # yarn

If you cloned the folio.md repository directly:

bash
bun run build    # bun
npm run build    # npm
yarn build       # yarn

The build fails if any internal link in your MDX files points to a page that doesn’t exist. Fix any broken links before deploying.

Deploying to GitHub pages

Add a workflow at .github/workflows/deploy.yml. Choose the tab for your package manager:

Bun

yaml.github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0        # needed for "last updated" git dates
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun run build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/deploy-pages@v4
        id: deployment

npm

yaml.github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install
      - run: npm run build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/deploy-pages@v4
        id: deployment

yarn

yaml.github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: yarn
      - run: yarn build
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/deploy-pages@v4
        id: deployment

::: note If you serve the site from a subdirectory, for example https://user.github.io/my-repo/, set base: "/my-repo" in astro.config.ts and siteUrl: "https://user.github.io/my-repo" in folio.config.ts. :::

Deploying to GitLab pages

Add a pipeline at .gitlab-ci.yml:

Bun

yaml.gitlab-ci.yml
pages:
  image: oven/bun:latest
  script:
    - bun install
    - bun run build
    - mv dist public   # GitLab Pages expects output in public/
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

npm / yarn

yaml.gitlab-ci.yml
pages:
  image: node:20
  script:
    - npm install          # or: yarn
    - npm run build        # or: yarn build
    - mv dist public
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

::: note If you serve your project from a subpath such as https://user.gitlab.io/my-repo/, set base: "/my-repo" in astro.config.ts and siteUrl: "https://user.gitlab.io/my-repo" in folio.config.ts. :::

Custom server

Copy dist/ to any static file host. With nginx:

nginxnginx.conf
server {
    listen 80;
    root /var/www/my-docs/dist;
    index index.html;
    location / {
        try_files $uri $uri/ $uri.html =404;
    }
}