Command line (ee-cdn-cli)
@evolving-edge/ee-cdn-cli is an npm package with two commands: ee-deploy publishes a folder of static files as a workload, and ee-domain claims a custom domain for your project. Use them from your own computer, or from CI every time you push.
It works with the output of any static site generator, and with hand-written HTML.
Before you begin
Section titled “Before you begin”You need:
- Node.js 22.12 or later.
- Windows (x64), macOS or Linux (x64 or arm64).
- A deploy token from the portal, under Workload → Deploy Tokens. See Deploy tokens.
- Your project ID (it starts
proj_), if your token is scoped to one project. - A domain the network serves your site on. It must be claimed for your project and active before you deploy to it. See Custom domains.
Your first deploy
Section titled “Your first deploy”Build your site, then run ee-deploy in your project folder. With npx there’s nothing to install:
export EE_CDN_TOKEN=<your deploy token>npx @evolving-edge/ee-cdn-cli --domain www.example.com --project proj_abc123ee-deploy finds your generator’s output folder and says what it chose, for example Deploying ./dist (detected: Astro). To name the folder yourself, put it first: npx @evolving-edge/ee-cdn-cli ./public --domain www.example.com.
To check the folder packages correctly without publishing anything, add --dry-run.
A new deploy takes up to about 90 seconds to reach every node.
Installing it in a project
Section titled “Installing it in a project”To pin a version for a project, add it as a dev dependency and call ee-deploy from a script:
npm install -D @evolving-edge/ee-cdn-cli{ "scripts": { "deploy": "ee-deploy --domain www.example.com" }}ee-deploy [directory] --domain <host> [options]| Argument | What it is |
|---|---|
[directory] |
The built site to publish. Optional: see Finding the output folder. |
--domain, -d <host> |
The hostname the network serves this workload on. Required. |
Finding the output folder
Section titled “Finding the output folder”Without a directory, ee-deploy works out the output folder from your project’s dependencies or your generator’s config file. It recognises Astro, Next.js (static export), Nuxt, SvelteKit, Docusaurus, VitePress, Gatsby, Hexo, Eleventy, Hugo, Jekyll, MkDocs, mdBook, Sphinx, Zola and Vite.
It never guesses. If it finds no generator, finds two, or the folder has no index.html, it stops and asks you to name the directory.
Options
Section titled “Options”| Option | What it does |
|---|---|
--project <id> |
Project ID (proj_…). Required if your token is scoped to a project. |
--name <name> |
Workload name. Defaults to the domain. |
--level <0|1|2> |
Encryption level. Defaults to 0, a public site. See encryption levels. |
--token <token> |
Deploy token. Defaults to $EE_CDN_TOKEN. Prefer the environment variable, so the token stays out of your shell history. |
--build <id> |
Build configuration ID, to use settings saved in the portal. |
--org <id> |
Organisation ID. |
--trailing-slash |
Redirect /about to /about/. See Routing. |
--clean-urls |
Serve /about from about.html. |
--dry-run |
Package the folder but don’t upload it. Leaves the packaged .ee file on disk. |
--quiet, -q |
Print errors only. |
--builder <path> |
Use a packaging tool already on disk instead of downloading one. |
--builder-version <v> |
Use one version of the packaging tool instead of the latest. Defaults to $EE_BUILDER_VERSION. |
--lockfile <path> |
Where to record the packaging tool’s checksum. Defaults to .ee-builder-lock.json. |
--cache-dir <path> |
Where to keep the downloaded packaging tool. Defaults to ~/.cache/evolving-edge. |
--version, -v |
Print the version. |
--help, -h |
Print every option. |
Environment variables
Section titled “Environment variables”| Variable | What it sets |
|---|---|
EE_CDN_TOKEN |
The deploy token. |
EE_CDN_PROJECT_ID |
The default for --project. |
EE_CDN_BUILD_ID |
The default for --build. |
EE_BUILDER_VERSION |
The default for --builder-version. |
Deploy tokens
Section titled “Deploy tokens”Create a deploy token in the portal under Workload → Deploy Tokens.
- Scope it to one project where you can. A token for one project can’t publish to another.
- Grant
workload:writeto deploy content, andrelease:writeif you need it. - Revoke it at any time from the portal. A revoked token stops working immediately.
- Keep it out of your repository. In CI, store it as a secret.
Routing: trailing slashes, clean URLs and redirects
Section titled “Routing: trailing slashes, clean URLs and redirects”Pages are served at exactly the address that matches a file. /about/ serves about/index.html, and /about is a 404 unless you say otherwise.
There are two settings, and two ways to turn each one on:
| Setting | Flag | Line in _redirects |
|---|---|---|
Redirect /about to /about/ |
--trailing-slash |
# ee:trailing-slash on |
Serve /about from about.html |
--clean-urls |
# ee:clean-urls on |
A flag writes its line into the _redirects file in your output folder, creating the file if there isn’t one, so the setting travels with the deploy. If your own _redirects already sets one, including to off, your file wins.
Static Site Generators says which one your generator needs.
ee-deploy checks your _redirects and _headers files while packaging. It stops if a redirect rule can’t work, and prints a warning for each header rule it has to drop.
Deploying from GitHub Actions
Section titled “Deploying from GitHub Actions”Store the token as a repository secret named EE_CDN_TOKEN, and the project ID as a repository variable named EE_CDN_PROJECT_ID. Then:
name: Deploy
on: push: branches: [main]
concurrency: # Never let two deploys race to repoint the same domain. group: deploy cancel-in-progress: false
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' cache: npm - run: npm ci - run: npm run build - name: Publish env: EE_CDN_TOKEN: ${{ secrets.EE_CDN_TOKEN }} EE_CDN_PROJECT_ID: ${{ vars.EE_CDN_PROJECT_ID }} run: npx --yes @evolving-edge/ee-cdn-cli --domain www.example.comAny CI system works the same way: install Node.js, build, set the two variables, and run the command.
The packaging tool and its lockfile
Section titled “The packaging tool and its lockfile”ee-deploy downloads a small packaging tool the first time it runs, and caches it. It records the tool’s checksum in .ee-builder-lock.json and refuses a later download that doesn’t match.
- Commit
.ee-builder-lock.json, so CI uses the same tool you tested with. - In CI, pin a version with
--builder-versionorEE_BUILDER_VERSION. With the latest version and a committed lockfile, every new release of the tool stops your deploy with a checksum mismatch, on purpose, until you accept it. - If a deploy stops with a checksum mismatch, a new version of the tool has been published. Check the changelog for the release, then delete the lockfile, or update the checksum in it, and commit the change.
Custom domains
Section titled “Custom domains”ee-domain claims a domain for a project from the command line. It reads EE_CDN_TOKEN and EE_CDN_PROJECT_ID, as ee-deploy does.
npx -p @evolving-edge/ee-cdn-cli ee-domain claim www.example.com --project proj_abc123 --waitIt prints the TXT and CNAME records to add at your DNS provider. With --wait, it keeps checking until the domain is active or the claim fails. If the package is installed in your project, run ee-domain by name.
| Command | What it does |
|---|---|
ee-domain claim <domain> |
Claims the domain for your project and prints the two DNS records |
ee-domain status <domain> |
Shows where the claim stands, and the records while it’s waiting for DNS |
ee-domain verify <domain> |
Checks for the TXT record now, without waiting for the next check |
| Option | What it does |
|---|---|
--project <id> |
The project the domain is for. Defaults to $EE_CDN_PROJECT_ID |
--wait |
Keep checking until the claim is active or fails |
--interval <seconds> |
Time between checks with --wait. Defaults to 30 |
--timeout <minutes> |
Stop waiting after this long. Defaults to 120 |
--json |
Print the response as JSON |
Use a deploy token scoped to the project. A token that isn’t scoped to one project is refused, because it doesn’t say which project the domain is for.
See Custom domains for what the records are, the statuses, and what to do if a claim fails.
The same package includes an Astro integration that publishes at the end of astro build, so there’s no separate deploy step:
import { defineConfig } from 'astro/config';import eeCdn from '@evolving-edge/ee-cdn-cli/astro';
export default defineConfig({ site: 'https://www.example.com', trailingSlash: 'always', build: { format: 'directory' }, integrations: [ // Keep this last, so it packages what the other integrations write. eeCdn({ deploy: { domain: 'www.example.com', projectId: 'proj_abc123' } }), ],});Set EE_CDN_TOKEN as above. Both Astro settings are required: without them, pages are written and linked in a way the network doesn’t serve. List eeCdn last in integrations, or files written by integrations after it, such as a sitemap, are left out of what’s published.
After a deploy
Section titled “After a deploy”- Allow up to about 90 seconds for a new deploy to reach every node.
- Every deploy is kept. Each one is stored under its own content address and never changes, so going back to an earlier version means pointing your domain at it again. See URLs and aliases.
Troubleshooting
Section titled “Troubleshooting”| What you see | What to check |
|---|---|
| A page works with a trailing slash but not without | Pass --trailing-slash, or add # ee:trailing-slash on to _redirects. |
/about is a 404 but /about.html works |
Pass --clean-urls, or add # ee:clean-urls on to _redirects. |
| The deploy is refused for your domain | Claim the domain for this project first. See Custom domains. |
| It stops and asks for a directory | It couldn’t tell which folder to publish. Name it: ee-deploy ./dist --domain …. |
The deploy stops on a _redirects rule |
The message names the line. See Checking your file. |
| A checksum mismatch for the packaging tool | See The packaging tool and its lockfile. |
| An authorisation error | Check EE_CDN_TOKEN is set, hasn’t been revoked, and is scoped to the project you passed. |
| It doesn’t run on your computer | Check Node.js is 22.12 or later, and that you’re on Windows (x64), macOS, or Linux (x64 or arm64). |
Other API access
Section titled “Other API access”There’s no public API reference for other endpoints. If you need programmatic access beyond publishing workloads, contact Customer Support.
For Level 1 content in the browser, see the Browser SDK.
Next: Static Site Generators >
