Eden Deploy takes an existing Eve project directory and runs the real Eve application on Cloudflare. It does not rewrite the project or replace Eve's providers, databases, Workflow World, authentication, schedules, channels, or sandbox.
Start with installation and account setup.
Eden runs the project's own eve build, starts the official project-local
eve start --host 0.0.0.0 --port 8080 supervisor inside one bounded Cloudflare
Container (instance_type: "basic", max_instances: 1), and routes the
public surface through one generic Worker.
Eden owns build orchestration, packaging, publication, deployment identity, and exact cleanup. Eve remains the application and workflow authority.
Before deploying, confirm:
eden --helpstarts successfully.npx wrangler@4.120.0 whoamishows the intended Cloudflare account on the Workers Paid plan, which Containers requires.- Docker or OrbStack is running with Linux/amd64 support.
- The selected Eve root contains
package.jsonandpnpm-lock.yaml. package.jsonhas an exactpackageManager: "pnpm@..."value.- The matching dependencies are installed and
node_modules/.bin/everesolves to the project-local Eve package. - The project declares
just-bashas a production dependency (Eve^3.1.0; for examplejust-bash: "3.4.2"). Eve's default sandbox falls back tojust-bashinside Eden's isolated builder, which has no Docker daemon or/dev/kvm; without the declarationeve buildfails withCannot find package 'just-bash'. - Every provider, credential, database, external API, and Workflow World required by the Eve project is reachable from Cloudflare.
From the Eve project root, these checks should succeed:
node -p "JSON.parse(require('node:fs').readFileSync('package.json', 'utf8')).packageManager"
test -f pnpm-lock.yaml
pnpm install --frozen-lockfile
test -x node_modules/.bin/eve
docker versionEden supports pinned pnpm Eve projects in this release. Bun lockfiles and native Windows are not supported.
With no flags, eden deploy and eden preflight use the current directory,
the preview environment, and a target name derived deterministically from
the project's package.json name. From the Eve project root, eden deploy
is sufficient. For an explicit target, use a unique lowercase Worker name and
keep the same selectors for deploy and destroy:
PROJECT_ROOT="/absolute/path/to/my-eve-project"
ENVIRONMENT="preview"
WORKER_NAME="my-eve-preview-$(date +%s)"Use an absolute project path when following this guide. Eden does not search parent or sibling directories.
If the Eve application needs runtime values, create an owner-readable file outside the project and outside source control:
ENV_FILE="$HOME/.config/my-eve-project/preview.env"
mkdir -p "$(dirname "$ENV_FILE")"
chmod 700 "$(dirname "$ENV_FILE")"
touch "$ENV_FILE"
chmod 600 "$ENV_FILE"The file uses KEY=VALUE records:
PROJECT_PROVIDER_KEY=replace-with-the-project-owned-value
PROJECT_WORLD_URL=https://example.invalid
Use the names required by the Eve project. Do not copy these illustrative names unless the project actually consumes them.
Eden parses variable names, not secret values. Values flow through the protected
deployment path into the Container environment and Cloudflare secrets. They are
not placed in argv, image layers, generated artifacts, or normal logs.
Reserved host variables such as HOST, PORT, NITRO_*, NODE_ENV,
NODE_EXTRA_CA_CERTS, and Eden's identity variables are rejected.
deploy runs every required check inline. Preflight is useful when diagnosing a
project before allowing remote mutation:
eden preflight \
--project "$PROJECT_ROOT" \
--env "$ENVIRONMENT" \
--name "$WORKER_NAME" \
--env-file "$ENV_FILE"Omit --env-file when the project needs no additional runtime values.
Preflight builds and inspects the candidate but does not publish Cloudflare
resources.
eden deploy \
--project "$PROJECT_ROOT" \
--env "$ENVIRONMENT" \
--name "$WORKER_NAME" \
--env-file "$ENV_FILE"Again, omit --env-file when it is not needed.
A successful command prints progress lines and a summary ending with the
exact workers.dev URL on its own line. Eden promotes the generation only
after the public /eve/v1/health route reports the expected ready identity.
Pass --json to preflight, deploy, or destroy to print the
machine-readable result object instead, for scripts and CI.
Copy the printed URL:
DEPLOY_URL="https://replace-with-the-printed-workers-dev-url"
curl --fail --silent "$DEPLOY_URL/eve/v1/health"The response must report status: "ready". Then use the Eve project's normal
public interface to execute one representative request. Health proves startup;
a normal application request proves that the project-owned providers and
services work from the deployed environment.
Destroy with the same project, environment, and Worker name:
eden destroy \
--project "$PROJECT_ROOT" \
--env "$ENVIRONMENT" \
--name "$WORKER_NAME"destroy rejects --env-file; cleanup does not need application secrets.
Destroy requires Eden's immutable ownership record, checks the current remote
identity, removes only that Worker and Container application, verifies bounded
absence, and only then clears the target's CURRENT pointer. It never deletes
by prefix or broad account search.
Destroy also removes the managed-registry image tag
(eden-eve-<target>-<generation>:candidate in registry.cloudflare.com) for
every generation the ownership records prove this exact target pushed,
including images retained by aborted pushes, then verifies each ref is gone.
Any image left behind is reported in the destroy output with its exact
repository:tag ref; remove only the listed refs with
npx wrangler@4.120.0 containers images delete <repository:tag> and never
filter by prefix.
After a healthy deployment is promoted, deploy also verifies and removes its
exact retained local Docker image and publication tags. The immutable
generation label must match before Eden removes anything. An indeterminate
publication keeps its exact local evidence instead of guessing at cleanup.
Confirm the URL is no longer reachable:
if curl --fail --silent "$DEPLOY_URL/eve/v1/health"; then
echo "unexpected: deployment is still reachable" >&2
exit 1
fiAlso compare the Cloudflare Workers list and the Container inventory before and after the run:
npx wrangler@4.120.0 containers list
npx wrangler@4.120.0 containers images listRequire zero new Worker, Container, or managed-registry image residue
associated with WORKER_NAME. An unreachable URL alone is not sufficient
cleanup evidence.
Maintainers validating Eden against the current Eve release should also follow the current Eve compatibility runbook.
--project defaults to the current directory and --env defaults to
preview. --env accepts preview or production. preflight and
deploy derive the target name from package.json when --name is omitted;
--env production and destroy always require an explicit --name.
Use preview first. Production is a separate explicit target for downstream users that intentionally operate preview and production deployments. A preview success does not establish a production SLA.
The Eve project's providers, models, credentials, databases, queues, external APIs, channels, schedules, sandbox, authentication, authorization, and configured Workflow World remain authoritative. Eden never substitutes a model provider or service silently.
Eden returns 404 for public requests to Workflow queue delivery routes
(/.well-known/workflow/v1/flow and /step). Token-bearing
webhook/<token> and manifest.json routes remain forwarded to Eve.
The container's own requests to its exact public hostname are intercepted
and delivered back into the same container over the internal port. Other
outbound hosts go directly to the internet without Worker interception.
HTTPS self-origin delivery trusts Cloudflare's runtime-mounted Containers CA.
WORKFLOW_LOCAL_BASE_URL remains the public origin, preserving Eve-generated
callback URLs.
A preview deployment that boots Eve's local Workflow World proves health, startup, and fresh request handling only. Container-local disk and process memory are wiped when the Container sleeps: a sleep or restart reinitializes local World state. Schedules still fire while the Container sleeps (see "Schedules" below).
Production durability requires a project-configured, Cloudflare-reachable,
durable Eve-compatible Workflow World such as Postgres (for example
@workflow/world-postgres). See
Durable state (Postgres World) for the exact
tested setup. This release runs one logical Container instance
and does not promise horizontal scaling or custom domains.
Authored Eve schedules (agent/schedules/*) keep firing while the Container
sleeps. When eve build reports schedules, Eden adds one every-minute
Cloudflare Cron Trigger to the generated Worker. Each minute the Worker
checks whether any schedule's next tick lands within the next four minutes;
when one does it issues an internal wake request to the Container so Eve's
own in-process Nitro scheduler fires the tick itself — each schedule runs
exactly once per cron tick, evaluated in UTC like on Vercel.
Standard 5-field cron expressions (minute hour day-of-month month day-of-week) are supported — the same subset Eve documents and Vercel Cron
evaluates. A schedule using anything else (for example a seconds field or an
@daily shortcut) cannot be evaluated ahead of time, so eden deploy warns
and that schedule only fires while the Container is already awake.
Because the every-minute trigger exists to wake the Container, a project with schedules pays one scheduled invocation per minute (~43k/month), which is well inside the Workers Paid allocation.
For testing sleep behavior, EDEN_EVE_CONTAINER_SLEEP_AFTER=<duration>
(for example 90s) overrides the Container's sleepAfter at deploy time.
Experimental. With Eve 0.68.0, add @moinulmoin/eden-world-cloudflare
to the agent project's production dependencies and select it in agent.ts:
experimental: {
workflow: { world: "@moinulmoin/eden-world-cloudflare" },
},Eden provisions one SQLite-backed Durable Object on your Cloudflare account.
Workflow state and stream chunks live outside the Container's disposable disk;
queue alarms wake the Container for workflow delivery. No database URL or
external database account is required. Eden supplies EDEN_WORLD_URL and
CBOR_NATIVE_ACCELERATION_DISABLED=true automatically. The World RPC endpoint
is private to intercepted Container requests; public /__eden/world/* requests
return 404.
eden destroy permanently deletes this state along with the Worker. It is not
a restart mechanism: preserve the Worker and Durable Object when restarting a
Container. Cloudflare's Worker deletion contract
deletes the Worker's Durable Object namespaces; no deleted_classes migration
is needed when deleting the whole Worker.
Limitation: updates erase this state. eden deploy does not update an
existing target, so shipping new agent code today means eden destroy then
eden deploy, and that deletes the Durable Object's data. State survives
Container sleep and restarts, not redeploys. If you need state to survive
code updates, use the Postgres World below; its data lives outside the
Worker.
Not yet verified: automatic sleep. In the live test, a Container using this World was still running 45 seconds after its last client disconnected, with a 30-second sleep setting. Durability across a real Container restart is proven; whether and when the Container auto-sleeps with this World is not. Budget for an always-on Container (about $12/month at Cloudflare's published rates) until this is confirmed.
Container-local disk and process memory are wiped whenever the Container
sleeps or is replaced, so Eve's default local Workflow World loses pending
approvals and in-flight sessions. Eden has tested the Postgres World
(@workflow/world-postgres) end to end: a pending tool approval survived a
full eden destroy + eden deploy container replacement. This section is
the tested recipe; other durable Worlds are project-owned and untested here.
Any Postgres reachable from Cloudflare works — for example a Neon project or a Supabase project. Cloudflare itself has no hosted Postgres; the database is always external.
The connection URL must be a direct, unpooled connection that supports
LISTEN/NOTIFY. The World delivers live session events over Postgres
LISTEN/pg_notify. Transaction-mode poolers — Neon's -pooler host
(PgBouncer) and Supabase's pooler on port 6543 — accept LISTEN but never
deliver notifications, so GET /eve/v1/session/<id>/stream returns headers
and then hangs forever even though events persist in the database. On Neon
use the DATABASE_URL_UNPOOLED value (the host without -pooler); on
Supabase use the direct connection on port 5432. Sessions still execute
against a pooled URL — only live streaming silently breaks — so this is
easy to miss; eden preflight warns when it sees a pooled URL.
Eve pins and validates its World at eve build, so the Postgres World
version must match the @workflow/world version your Eve release bundles.
Eve 0.68.0 bundles @workflow/world 5.0.0-beta.39 and pairs with:
pnpm add @workflow/world-postgres@5.0.0-beta.47For other Eve versions, install the @workflow/world-postgres release whose
@workflow/world dependency matches the one Eve bundles; eden preflight
and eden deploy fail with an EVE_WORLD_PAIRING check when the installed
release would not pair.
export default {
// …
experimental: { workflow: { world: "@workflow/world-postgres" } },
};This field is resolved at eve build; WORKFLOW_TARGET_WORLD is ignored by
the Eve runtime plugin.
Create the --env-file outside the project root — a file inside the
project is snapshotted into the image and the deploy fails with
SECRET_EXCLUSION_FAILED:
WORKFLOW_POSTGRES_URL=postgres://<direct-unpooled-host>/<database>
Use the direct URL described above; WORKFLOW_POSTGRES_URL falls back to
DATABASE_URL when unset. Nothing else is needed: Eden sets
CBOR_NATIVE_ACCELERATION_DISABLED in the container image itself, exempts
the optional cbor-extract native addon (cbor-x then uses its pure-JS path),
and runs the World's idempotent schema migration (node_modules/.bin/bootstrap,
drizzle migrations + graphile-worker schema) inside the disposable deploy
container against the env-file URL before publishing. A migration failure
fails the deploy with EVE-WORLD_MIGRATION_FAILED.
eden deploy --project "$PROJECT_ROOT" --env preview \
--name "$WORKER_NAME" --env-file "$ENV_FILE"Verify durability, not just health:
curl --fail --silent "$DEPLOY_URL/eve/v1/health" # status: "ready"
curl -N "$DEPLOY_URL/eve/v1/session/<id>/stream" # must emit NDJSON, not just headersThen start a turn that parks on an approval, run eden destroy + eden deploy, and confirm the pending approval is still resolvable. If the stream
hangs with headers only, the URL is pooled — fix step 3.
| Symptom | Check |
|---|---|
eden is not found |
Follow the PATH section in Install Eden. |
| Project or lockfile validation fails | Confirm the selected root, exact pnpm packageManager, root lockfile, frozen install, and project-local Eve executable. |
| Docker build cannot start | Start Docker or OrbStack and verify Linux/amd64 support with docker version. |
| Cloudflare account or origin resolution fails | Run npx wrangler@4.120.0 whoami and confirm the intended account and workers.dev subdomain. |
| Health never reaches ready | Inspect the Eve project's provider, Workflow World, and startup requirements; Eden does not replace them. |
| Destroy refuses cleanup | Preserve the target records and inspect the reported ownership or identity mismatch. Never broaden deletion by prefix. |
Return to the documentation index.