Deploy a Jekyll site
Publish a Jekyll site on your own domain, from your computer or from GitHub Actions. If your site is on GitHub Pages today, see Moving from GitHub Pages.
| Build command | bundle exec jekyll build |
| Output folder | _site |
| Settings you need | url, baseurl: "", and include: [_redirects, _headers] if you use them |
| Routing | Jekyll’s default links end in .html and work as they are. Pretty permalinks need --trailing-slash; extensionless ones need --clean-urls |
Before you begin
Section titled “Before you begin”You need:
- A Jekyll site that builds on your computer with
bundle exec jekyll 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
www.example.com, and access to its DNS settings. - Node.js 22.12 or later, on Windows (x64), macOS, or Linux (x64 or arm64), to deploy from your computer. The deploy tool is an npm package; Jekyll itself doesn’t need Node.js, and the GitHub Action below brings its own.
1. Configure Jekyll
Section titled “1. Configure Jekyll”Set the site’s full address, and serve it from the root of the domain:
url: "https://www.example.com"baseurl: ""jekyll-feed, jekyll-sitemap and jekyll-seo-tag use url for absolute links. Build with JEKYLL_ENV=production so they use it.
Choose how pages are addressed
Section titled “Choose how pages are addressed”What your permalink setting looks like decides one deploy flag:
| Your permalinks look like | Jekyll writes | Deploy with |
|---|---|---|
/2026/09/29/welcome.html (the default date style) |
…/welcome.html |
Nothing extra |
/about/ or permalink: pretty |
about/index.html |
--trailing-slash |
/about (no slash, no .html) |
about.html |
--clean-urls |
Sites often mix these: minima’s posts use the default style, while its pages set /about/. Passing both flags is fine.
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 www.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”JEKYLL_ENV=production bundle exec jekyll buildnpx @evolving-edge/ee-cdn-cli _site --domain www.example.com --project proj_abc123 --trailing-slashee-deployfinds_siteby 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 examplewww.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
- uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' bundler-cache: true
- name: Build run: bundle exec jekyll build env: JEKYLL_ENV: production
- name: Deploy uses: evolving-edge/ee-cdn-cli@v0.4.0 with: directory: _site domain: ${{ vars.EE_DOMAIN }} project: ${{ vars.EE_CDN_PROJECT_ID }} token: ${{ secrets.EE_CDN_TOKEN }} trailing-slash: trueThe Action brings its own Node.js, so the workflow needs no setup-node step. Set clean-urls: true as well if your permalinks have no extension. To keep a new release of the packaging tool from changing your deploys, pin it with builder-version; see The GitHub Action.
Moving from GitHub Pages
Section titled “Moving from GitHub Pages”- Add the workflow above. GitHub Pages can build a branch with no workflow at all; Evolving Edge deploys what your workflow builds. A
Gemfilethat uses thegithub-pagesgem keeps working, and so does one that uses Jekyll 4. - Set
baseurl: "". A project site atyou.github.io/repo/moves to the root of its own domain. - Extensionless links. GitHub Pages quietly serves
/aboutfromabout.html. Deploy with--clean-urlsto keep those links working. - The
CNAMEfile in your repository does nothing here, and is harmless to keep. Your domain is set up by claiming it. site.githubdata. Themes that readsite.github.*get it from GitHub Pages automatically. In your own workflow,jekyll-github-metadatamay need a token (JEKYLL_GITHUB_TOKEN) to fill it in.
Redirects, 404 page and caching
Section titled “Redirects, 404 page and caching”Redirects. Add a _redirects file at the project root:
/old-post.html /2026/09/29/new-post.html 301/notes/* /blog/:splat 301Jekyll skips files whose names start with an underscore, so tell it to copy this one (and _headers, if you add it):
include: - _redirects - _headersRules can be 301 or 302, and * and :splat wildcards work. Redirects apply to public (Level 0) sites. Pages made by jekyll-redirect-from keep working too.
404 page. A 404.html at the site root, with permalink: /404.html, is served with a 404 status for any address that doesn’t exist. minima and most themes include one. 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. Jekyll doesn’t add hashes to asset names (minima’s assets/main.css has none), so leave caching as it is. Don’t mark assets/ as immutable, or a changed stylesheet can stay in browsers’ caches for a year.
What doesn’t carry over
Section titled “What doesn’t carry over”- Subfolder deploys. A site owns its whole domain.
- Automatic branch builds. Deploys come from your workflow or your computer.
- Deploy previews for each pull request. To preview, deploy to a second domain.
Troubleshooting
Section titled “Troubleshooting”| What you see | Why | What to do |
|---|---|---|
/about is a 404 but /about/ works |
The trailing-slash redirect isn’t on | Deploy with --trailing-slash |
/about is a 404 and the file is about.html |
Extensionless permalinks | Deploy with --clean-urls |
Redirects in _redirects don’t work |
Jekyll didn’t copy the file | Add it to include: in _config.yml |
| Styles are missing after moving from GitHub Pages | baseurl still has the old /repo path |
Set baseurl: "" |
Feed or sitemap links point at localhost:4000 |
Built without JEKYLL_ENV=production, or url not set |
Set url and build with JEKYLL_ENV=production |
| 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.
