Deployment

Deploying Valaxy is very easy. We suggest that you build and deploy to any platform using third party CI.

Manual Deployment ​

bash
pnpm run build
bash
bunx valaxy build --ssg
bash
yarn build
bash
npm run build

Run the build command to build, and the dist directory contains the built content.

SSG respects Node’s heap limit. For a 4 GiB build environment, start with a 1.5 GiB heap to leave room for the bundler and other processes:

bash
NODE_OPTIONS=--max-old-space-size=1536 pnpm build

Deploying under a base path ​

When the site is served below the domain root, configure Vite’s base with both leading and trailing slashes. siteConfig.url is the canonical site URL; it does not replace the asset base. For example, a GitHub Pages project site at https://user.github.io/repo/ uses:

valaxy.config.ts
ts
import { defineValaxyConfig } from 'valaxy'

export default defineValaxyConfig({
  siteConfig: {
    url: 'https://user.github.io/repo/',
  },
  vite: {
    base: '/repo/',
  },
})

Starting with Valaxy v1.0.0-rc.4, this behavior is aligned with VitePress and is enabled by default; there is no separate compatibility switch. The final base resolved by Vite is shared by the page, excerpt/router, and local-search Markdown renderers.

Root-absolute links and static assets written in Markdown are adjusted automatically:

md
[Guide](/guide/)
![Logo](/logo.png)
[Download PDF](/manual.pdf)

For dynamic URLs in Vue components or theme configuration, use withBase():

vue
<script setup lang="ts">
import { withBase } from 'valaxy'

const logo = '/logo.png'
</script>

<template>
  <img :src="withBase(logo)" alt="Logo">
</template>

Markdown page and file links receive base directly. Markdown images are normalized for Vue/Vite’s asset pipeline, which applies the final base to root-absolute public resources in the generated output.

External URLs and relative paths are left unchanged. Raw HTML <a> links are also left unchanged so you can deliberately link outside the configured base. Raw HTML images can still be transformed by Vue/Vite.

Page URLs ​

A page such as pages/posts/hello.md is written to dist/posts/hello.html. Its canonical URL has no trailing slash: /posts/hello. The build then copies that HTML to dist/posts/hello/index.html, so /posts/hello/ returns the same page on a static host that looks up a directory index. The copy is made after the sitemap, which lists the canonical URL once. The page’s canonical link points at the URL without a trailing slash.

pages/about/index.md is the directory URL /about/ (and /about on hosts that map a directory index to the shorter path). pages/404.md is built as 404.html for hosts that serve that file for unknown paths. /404 is left out of the sitemap.

In development, the router also accepts a trailing slash on the same route. The extra index.html is what makes that URL work after a static deploy, including hosts that answer unknown paths with 404.html before any client-side router runs.

Third Party Deployment ​

TIP

The configuration files for the following third-party deployments are built into the Valaxy template project. You can use them as needed.

If the deployment fails, we recommend that you first check for potential build errors locally using npm run build.

GitHub Pages ​

TIP

Repositories named your-username.github.io are served from / and do not need a custom base. Other repository names are supported as project sites; configure base: '/repository-name/' as described above.

.github/workflows/gh-pages.yml
gh-pages.yml
yml
name: GitHub Pages

on:
  push:
    branches:
      # The branch where the project source code resides
      # 项目源代码所在的分支
      - main
      - master
      - valaxy
  workflow_dispatch:

# Publish the built site with GitHub Pages. The workflow token can read
# the repository and upload the artifact.
permissions:
  contents: read
  pages: write
  id-token: write

# One deployment at a time. Let an in-progress production deploy finish.
concurrency:
  group: pages
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          # Git dates for posts need the full history.
          # 文章的 Git 日期需要完整提交历史。
          fetch-depth: 0

      # Read the exact pnpm version from package.json's packageManager field.
      - uses: pnpm/action-setup@v6

      - name: Use Node.js LTS
        uses: actions/setup-node@v7
        with:
          node-version: lts/*

      - name: Setup Pages
        uses: actions/configure-pages@v6

      - name: Install dependencies
        # The scaffold ships package.json without a lockfile.
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v5
        with:
          path: dist
          include-hidden-files: true

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v5

When you use pnpm create valaxy to create a template project, it contains the file .github/workflows/gh-pages.yml for the CI workflow of GitHub Actions.

  • Push the project to your GitHub repository.
  • Open Settings -> Pages and choose GitHub Actions as the Pages source.

The workflow uses Node.js LTS and the pnpm version pinned in package.json’s packageManager field, runs pnpm run build, and publishes the dist directory with GitHub’s Pages actions, including hidden resources such as .well-known/. The workflow token only needs contents: read, pages: write, and id-token: write. After choosing the source, re-run the workflow if the first run did not publish the site.

Change on.push.branches in gh-pages.yml to the branch where your source code lives. The default includes main.

Netlify ​

netlify.toml is built-in.

Vercel ​

  • On Vercel Dashboard, click Add New..., then click Project to create a project.
  • Select the repository you want to deploy and click Import and then set Framework Preset to Other and modify Build and Output Settings.
  • Turn on the switch on the right of the textbox and type dist, click Deploy.
  • Wait for ribbons to drop on the screen, then visit your website.
netlify.toml
netlify.toml
toml
[build]
publish = "dist"
command = "pnpm run build"

[build.environment]
NODE_VERSION = "22"

[[redirects]]
from = "/*"
to = "/index.html"
status = 200

[[headers]]
for = "/manifest.webmanifest"

[headers.values]
Content-Type = "application/manifest+json"

Cloudflare Pages ​

  • Login to your Cloudflare account and navigate to "Workers and Pages" page.
  • Click Create a project and Connect to Git, then select your GitHub or GitLab repository and click Begin setup.
  • Select your Production branch.
  • Set Build output directory to pnpm build .
  • Set Build output directory to dist .
  • Then click "Save and Deploy".

Nginx ​

Nginx Docs

Here is an example of an Nginx server block configuration nginx.conf. This configuration includes rules for gzip compression of common text-based resources, serving static files for a Valaxy site with appropriate caching headers, and handling cleanUrls: true.

nginx.conf
nginx.conf
nginx
server {
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    listen 80;
    server_name _;
    index index.html;

    location / {
        # content location
        # root /app;
        root /usr/share/nginx/html;

        # exact matches -> reverse clean urls -> folders -> not found
        try_files $uri $uri.html $uri/ =404;

        # non existent pages
        error_page 404 /404.html;

        # a folder without index.html raises 403 in this setup
        error_page 403 /404.html;

        # adjust caching headers
        # files in the assets folder have hashes filenames
        location ~* ^/assets/ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
}

This configuration assumes that the built Valaxy site is located in the /usr/share/nginx/html directory on the server. If your site files are located elsewhere, adjust the root directive accordingly.

Docker ​

Docker Docs

Here is an example Dockerfile for building a Valaxy site and deploying it to an Nginx server.

Refer to the Nginx section for the nginx.conf configuration and place it in the same directory as the Dockerfile.

Dockerfile
Dockerfile
Dockerfile
FROM node:22.12-alpine as build-stage

WORKDIR /app
RUN corepack enable

COPY .npmrc package.json pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store \
    pnpm install --frozen-lockfile

COPY . .
RUN pnpm build

FROM nginx:stable-alpine as production-stage

COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Others ​

You can also use Render to host your website.

TIP

Valaxy is also a static site like VitePress. You can refer to the VitePress Deployment Guide for deployment.

Contributors