Skip to content

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.

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.

Build your site, then run ee-deploy in your project folder. With npx there’s nothing to install:

Terminal window
export EE_CDN_TOKEN=<your deploy token>
npx @evolving-edge/ee-cdn-cli --domain www.example.com --project proj_abc123

ee-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.

To pin a version for a project, add it as a dev dependency and call ee-deploy from a script:

Terminal window
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.

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.

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.
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.

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:write to deploy content, and release:write if 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.

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.com

Any CI system works the same way: install Node.js, build, set the two variables, and run the command.

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-version or EE_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.

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.

Terminal window
npx -p @evolving-edge/ee-cdn-cli ee-domain claim www.example.com --project proj_abc123 --wait

It 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:

astro.config.mjs
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.

  • 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.
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).

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 >