Hosting your site

Contents â–¾

This guide covers deploying your Hugo site built with the sans theme to popular hosting platforms. All configurations include Pagefind search indexing.


GitHub Pages

GitHub Pages offers free hosting for static sites directly from your repository.

Note: Before deploying your blog on github pages make sure that the following configuration is set in your hugo.toml file.

TOML
1
2
3
baseURL = "https://yourusername.github.io/your-blog"
canonifyURLs = true  
relativeURLs = false  

If your blog is on a subdomain (i.e. with /your-repo-name rather than just yourusername.github.io), make sure that you include the full url with repo-name as well. Do not include slash at the end.

Make sure that canonifyURLs is set to true and relativeURLS is set to false. Errors may occur if this is not done.

Enable GitHub Pages

  1. Go to your github repository Settings → Pages
  2. Under Source, select GitHub Actions
  3. Go to Actions→ New Workflow and search for hugo. Github automatically generates a hugo.yml at your-hugo-site/.github/workflows/hugo.yml
  4. If you have disabled the search option for your hugo blog. Leave the hugo yml as it is.
  5. If you have enabled search function, remove the steps in hugo.yml and replace by the following:
    YML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
             steps:
          - name: Install Hugo CLI
            run: |
              wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
              && sudo dpkg -i ${{ runner.temp }}/hugo.deb
          - name: Install Dart Sass
            run: sudo snap install dart-sass
          - name: Checkout
            uses: actions/checkout@v4
            with:
              submodules: recursive
          - name: Setup Pages
            id: pages
            uses: actions/configure-pages@v5
          - name: Setup Node.js
            uses: actions/setup-node@v4
            with:
              node-version: '20'
              cache: 'npm'
          - name: Install Node.js dependencies
            run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
          - name: Install Pagefind
            run: npm install -g pagefind
          - name: Build with Hugo
            env:
              HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
              HUGO_ENVIRONMENT: production
            run: |
              hugo \
                --config hugo.toml \
                --minify \
                --baseURL "${{ steps.pages.outputs.base_url }}/"
          - name: Build Pagefind search index
            run: npx pagefind --site public --output-path public/pagefind
          - name: Upload artifact
            uses: actions/upload-pages-artifact@v3
            with:
              path: ./public
       
    Or replace the whole hugo.yml code with the following:
    YML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    
              # Sample workflow for building and deploying a Hugo site to GitHub Pages
    name: Deploy Hugo site to Pages
    
    on:
      # Runs on pushes targeting the default branch
      push:
        branches: ["master"]
    
      # Allows you to run this workflow manually from the Actions tab
      workflow_dispatch:
    
    # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
    permissions:
      contents: read
      pages: write
      id-token: write
    
    # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
    # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
    concurrency:
      group: "pages"
      cancel-in-progress: false
    
    # Default to bash
    defaults:
      run:
        shell: bash
    
    jobs:
      # Build job
      build:
        runs-on: ubuntu-latest
        env:
          HUGO_VERSION: 0.146.0
        steps:
          - name: Install Hugo CLI
            run: |
              wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
              && sudo dpkg -i ${{ runner.temp }}/hugo.deb
          - name: Install Dart Sass
            run: sudo snap install dart-sass
          - name: Checkout
            uses: actions/checkout@v4
            with:
              submodules: recursive
          - name: Setup Pages
            id: pages
            uses: actions/configure-pages@v5
          - name: Setup Node.js
            uses: actions/setup-node@v4
            with:
              node-version: '20'
              cache: 'npm'
          - name: Install Node.js dependencies
            run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
          - name: Install Pagefind
            run: npm install -g pagefind
          - name: Build with Hugo
            env:
              HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
              HUGO_ENVIRONMENT: production
            run: |
              hugo \
                --config hugo.toml \
                --minify \
                --baseURL "${{ steps.pages.outputs.base_url }}/"
          - name: Build Pagefind search index
            run: npx pagefind --site public --output-path public/pagefind
          - name: Upload artifact
            uses: actions/upload-pages-artifact@v3
            with:
              path: ./public
    
      # Deployment job
      deploy:
        environment:
          name: github-pages
          url: ${{ steps.deployment.outputs.page_url }}
        runs-on: ubuntu-latest
        needs: build
        steps:
          - name: Deploy to GitHub Pages
            id: deployment
            uses: actions/deploy-pages@v4
       

Vercel

Vercel provides fast deployments with automatic SSL and global CDN.

Configuration

Create vercel.json in your project root:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/static-build",
      "config": {
        "distDir": "public"
      }
    }
  ],
  "framework": null,
  "buildCommand": "npm run build",
  "outputDirectory": "public",
  "cleanUrls": true,
  "trailingSlash": false,
  "ignoreCommand": "git diff --quiet HEAD^ HEAD ./"
}

This assumes that there is a package.json file at the base of your directory. This is already true if you previously installed pagefind for search functionality. If you have enabled search, your package.json should look something like this:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "name": "your-hugo-site",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
  "serve": "hugo server --disableFastRender",
  "build": "npx hugo && npx pagefind --site public --output-path public/pagefind",
  "dev": "npx hugo --destination public && npx pagefind --site public --output-path public/pagefind && hugo server --disableFastRender --buildDrafts --noHTTPCache"
},
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "hugo-extended": "^0.152.0"
  }
}

If you do not have enabled search, your package.json should look something like this:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "name": "my-sans-site",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
  "serve": "hugo server --disableFastRender",
  "build": "npx hugo",
  "dev": "npx hugo --destination public && hugo server --disableFastRender --buildDrafts --noHTTPCache"
},
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "hugo-extended": "^0.152.0"
  }
}

Deploy

  1. Via Vercel Dashboard:

    • Import your Git repository
    • Vercel auto-detects configuration
    • Click Deploy
  2. Via CLI:

    BASH
    1
    2
    3
    
       npm i -g vercel
       vercel
       


Netlify

Netlify offers continuous deployment with built-in form handling and serverless functions.

Configuration

Create netlify.toml in your project root:

TOML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[build]
  publish = "public"
  command = "hugo --minify && npx pagefind --site public --output-path public/pagefind"

[build.environment]
  HUGO_VERSION = "0.146.0"
  NODE_VERSION = "20"

[[redirects]]
  from = "/pagefind/*"
  to = "/pagefind/:splat"
  status = 200

Deploy

  1. Via Netlify Dashboard:

    • Connect your Git repository
    • Build settings are auto-detected from netlify.toml
    • Click Deploy site
  2. Via CLI:

    BASH
    1
    2
    3
    
       npm i -g netlify-cli
       netlify deploy --prod
       


Cloudflare Pages

Cloudflare Pages provides fast global deployment with integrated CDN and DDoS protection. Make sure that you have the same package.json files as those included in the vercel section above.

Configuration

  1. Connect Repository:

    • Go to Cloudflare Dashboard → Pages
    • Click Create a project
    • Connect your Git repository
  2. Build Settings:

    • Framework preset: None
    • Build command: npm run build
    • Build output directory: public
    • Environment variables:
      • HUGO_VERSION: 0.146.0
      • NODE_VERSION: 20

Deploy


Important Notes

Build Command

All platforms use the same build process:

BASH
1
npm run build

This runs:

BASH
1
hugo && npx pagefind --site public --output-path public/pagefind

Output Directory

Always use public as the output directory (Hugo’s default).

Hugo Version

Ensure your Hugo version in build configs matches your local development version. Current configs use Hugo 0.146.0 Extended.

Node.js Version

All configurations use Node.js 20 for consistency.