Deploy a VitePress site
Publish a VitePress site on your own domain, from your computer or from GitHub Actions.
| Build command | npm run docs:build |
| Output folder | docs/.vitepress/dist (or .vitepress/dist if your site is at the project root) |
| Settings you need | None; sitemap.hostname if you want a sitemap |
| Routing | The default links end in .html and work as they are. With cleanUrls: true, deploy with --clean-urls |
These steps assume the layout npx vitepress init creates: the site in docs/, and the scripts docs:dev, docs:build and docs:preview in package.json.
Before you begin
Section titled “Before you begin”You need:
- A VitePress site that builds on your computer with
npm run docs:build. - An Evolving Edge account that can deploy workloads. See Getting Started.
- A project in the portal, and its project ID (it starts with
proj_). - A deploy token from the portal, under Workload → Deploy Tokens, with
workload:write. Scope it to the project. See Deploy tokens. - The domain you want to serve the site on, for example
docs.example.com, and access to its DNS settings. - Node.js 22.12 or later, on Windows (x64), macOS, or Linux (x64 or arm64).
1. Configure VitePress
Section titled “1. Configure VitePress”Nothing is required: the site is served from the root of the domain, so leave base at its default (/).
Two optional settings:
export default { cleanUrls: true, // links without .html; deploy with --clean-urls sitemap: { hostname: 'https://docs.example.com' }, // writes sitemap.xml with absolute URLs};cleanUrls. By default VitePress writesguide/intro.htmland links to/guide/intro.html, and nothing more is needed. WithcleanUrls: trueit still writesguide/intro.htmlbut links to/guide/intro. Deploy with--clean-urlsso those links find their pages.sitemap.hostname. Without it, VitePress writes no sitemap.
2. Claim your domain
Section titled “2. Claim your domain”Only the project that claimed a domain can deploy to it, so claim it before your first deploy. In the portal, or from the command line:
export EE_CDN_TOKEN=<your deploy token>npx -p @evolving-edge/ee-cdn-cli ee-domain claim docs.example.com --project proj_abc123 --waitIt prints a TXT record and a CNAME record to add at your DNS provider, then waits until the domain is active. See Custom domains for the portal steps, root domains and Cloudflare.
3. Deploy from your computer
Section titled “3. Deploy from your computer”npm run docs:buildnpx @evolving-edge/ee-cdn-cli docs/.vitepress/dist --domain docs.example.com --project proj_abc123- Add
--clean-urlsif you setcleanUrls: true. ee-deployfindsdocs/.vitepress/distby itself if you leave the folder out.- Each deploy replaces the whole site on that domain. Allow up to about 90 seconds for a new deploy to reach every node.
4. Deploy from GitHub Actions
Section titled “4. Deploy from GitHub Actions”In your repository settings, add:
- a secret
EE_CDN_TOKENholding your deploy token - variables
EE_DOMAIN(for exampledocs.example.com) andEE_CDN_PROJECT_ID
Then create .github/workflows/deploy.yml:
name: Deploy to Evolving Edge
on: push: branches: [main] workflow_dispatch:
permissions: contents: read
concurrency: group: ee-deploy cancel-in-progress: false
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # only needed if lastUpdated is on
- uses: actions/setup-node@v4 with: node-version: 22 cache: npm
- name: Cache VitePress uses: actions/cache@v4 with: path: docs/.vitepress/cache key: ${{ runner.os }}-vitepress-${{ hashFiles('package-lock.json') }} restore-keys: ${{ runner.os }}-vitepress-
- run: npm ci - run: npm run docs:build
- name: Deploy env: EE_CDN_TOKEN: ${{ secrets.EE_CDN_TOKEN }} EE_CDN_PROJECT_ID: ${{ vars.EE_CDN_PROJECT_ID }} # Add --clean-urls if you set cleanUrls: true. run: npx --yes @evolving-edge/ee-cdn-cli docs/.vitepress/dist --domain ${{ vars.EE_DOMAIN }}Redirects, 404 page and caching
Section titled “Redirects, 404 page and caching”VitePress copies everything in docs/public/ to the site root, so that’s where _redirects and _headers go.
Redirects. Add a _redirects file at docs/public/_redirects:
/guide/old-page.html /guide/new-page.html 301/v1/* /guide/:splat 301Rules can be 301 or 302, and * and :splat wildcards work. Redirects apply to public (Level 0) sites.
404 page. VitePress always builds a 404.html, and Evolving Edge serves it with a 404 status for any address that doesn’t exist. To change it, set notFound in the theme config or add a NotFound layout. See Custom 404 pages.
Caching. HTML pages are checked on every request, so a new deploy shows as soon as it reaches the nodes. Other files are cached for an hour. VitePress names everything in /assets/ by content hash, so you can cache that folder for a year with docs/public/_headers:
/assets/* Cache-Control: public, max-age=31536000, immutableCheck first that nothing in docs/public/assets/ is copied in without a hash. See Caching hashed assets for a year.
What doesn’t carry over
Section titled “What doesn’t carry over”- Subfolder deploys. A site owns its whole domain, so
basestays/. - Deploy previews for each pull request. To preview, deploy to a second domain.
Troubleshooting
Section titled “Troubleshooting”| What you see | Why | What to do |
|---|---|---|
| Links work in the menu, but a refreshed page is a 404 | cleanUrls: true without --clean-urls |
Deploy with --clean-urls |
| Styles and scripts are 404s | base is set to a subfolder |
Remove base, or set it to / |
No sitemap.xml |
sitemap.hostname isn’t set |
Add it to the config |
| The deploy is refused for your domain | The domain isn’t claimed for this project | Claim it first |
No deploy token |
EE_CDN_TOKEN isn’t set |
Export it, or add the repository secret |
| An authorisation error on upload | The token is scoped to a project and no project was given | Pass --project (or set EE_CDN_PROJECT_ID) |
More in the command line troubleshooting.
