drangler, in One Page
drangler is the command-line tool for a Drupflare site's whole life: stand one up, keep it healthy, develop a module against it, and move sites on or off. Every command takes --json and prints the same object its text is built from.
📦 Install
bun add -g @drupflare/drangler
# or
npm i -g @drupflare/drangler
Every release also ships a single-file binary for Linux and macOS on x64 and arm64, and Windows on x64, with a
SHA256SUMS file beside it. drangler needs ssh and wrangler; drangler doctor checks both.
🚀 First Time
drangler runs on your own computer. Before the first deploy, install it with wrangler, sign in to
Cloudflare, and let doctor check the setup:
npm i -g @drupflare/drangler wrangler
wrangler login # opens a browser to approve access to your Cloudflare account
drangler doctor # checks ssh, wrangler and the sign-in, and says how to fix what is missing
Commands that read an existing server (migrate, preview, doctor --source) connect over SSH
with your usual keys. Commands that act on a deployed site take its address, and the owner token
that site claim stored in your system keychain.
Every command accepts these flags:
| Flag | What it does |
|---|---|
--dry-run | print what the command would do, and do none of it |
--json | print the report as one JSON object, for scripts |
--yes, -y | consent for anything that changes a live site; without it those refuse |
--site <origin> | the site to act on, such as https://my-site.example |
--token <token> | the owner token when it is not saved; DRUPFLARE_OWNER_TOKEN also works |
--verbose, -v | print every command and request drangler makes |
--quiet, -q | hide progress; the report still prints |
🎬 Common Jobs
Try Drupal on your laptop. One command clones the worker, downloads Drupal and the PHP
interpreter, checks the result and serves it at http://localhost:8787. Run it again and it reuses
the workspace.
drangler dev
Put it on Cloudflare. Deploy the same workspace, then claim the site to get the administrator
password and the owner token. The token goes into your system keychain without asking, so later
commands find it; --save also writes it to your user config.
drangler deploy
drangler site claim my-site.example --title "My Site" --save
Lost the owner token. It is shown once, at the claim. If you can write to the Cloudflare account
the site is deployed on, you can get it back, and --store saves it to the keychain:
drangler recover-token my-site.example --store
Copy an existing site to see it running. preview reads your current server with read-only
commands and brings up a working duplicate. The live site is not touched. Available from drangler
0.3; from 0.4 it finds the Drupal root itself, so the host is all it needs.
drangler preview --host [email protected]
Every choice it makes has a flag, a DRANGLER_PREVIEW_<NAME> variable and a prompt on a terminal, so
a script answers it without flags and a person answers it by typing. A flag wins over a variable, and
a question nobody can answer is refused rather than left waiting.
DRANGLER_PREVIEW_CONFIRM=old.example DRANGLER_PREVIEW_FOLLOW=mymodule=my-org/mymodule \
drangler preview --host [email protected]
Credentials the database holds, such as payment keys, mail logins and OAuth secrets, are blanked in
the duplicate and listed by name, so a copy cannot act as your live site. --carry-key <name> brings
one back. --follow module=owner/repo keeps a module current from git, --check <path> compares more
pages with the live site, and --deploy puts the copy on your Cloudflare account behind a Cloudflare
Access login that only you can pass. The full list is in Migrate.
Keep an eye on it. status says what is deployed, health says whether it is serving. Both
exit non-zero on a problem, so either can go in a monitor or a CI job.
drangler status my-site.example
drangler health my-site.example
Upgrade. Move the checkout to the latest release, deploy it, wait for the site to pick it up and run Drupal's database updates, in one step.
drangler site upgrade my-site.example
Get your data out. The whole database, as a file you own.
drangler migrate export --url my-site.example --out site.sql
🧰 Set Up and Run Locally
| Command | What it does |
|---|---|
doctor | Checks the toolchain, the Cloudflare credential and the config |
init | Connects this machine to a site and records where it went |
build | Clones the worker and builds it into a deployable tree |
validate | Everything that has to hold before dev or deploy works |
dev | Builds if needed, checks, then runs Drupal on your machine |
🚀 Deploy and Update
| Command | What it does |
|---|---|
deploy | Builds if needed, checks, then deploys to your account |
site claim <target> | Mints the administrator password and the owner token |
recover-token <target> | Gets a lost owner token back; --store keeps it |
update [worker] | Moves a checkout to another version, and its worker |
site upgrade <target> | Deploys, waits for the database replay, runs the updates |
site updb <target> | Reads Drupal's update chain and drives one step of it |
🩺 Operate a Site
| Command | What it does |
|---|---|
status <target> | What is deployed: plan, version, claim state |
health <target> | Probes a site and reports which cache tier answered |
heal <target> | Reports the repair ladder and performs the repairs it can |
reconcile <target> | What a site still owes the shipped release, and drives it |
sweep <target> | How much of the site is cached, and what the scheduler decided |
site invalidate | Purges cached pages by tag, or retires them all at once |
setup cloudflare <target> | Whether a Cloudflare account grant is connected; --disconnect revokes it |
setup mail <target> | Sending-domain onboarding: what is set up, and takes the next step |
setup identity <target> | The OpenID Connect provider: read it, set it or clear it |
🚚 Migrate
| Command | What it does |
|---|---|
preview | Surveys, converts and brings up a working duplicate of a site |
migrate survey | Reads a server-hosted Drupal over SSH, read-only |
migrate eligibility | Can this site move today, and what would have to change |
migrate plan | Scores a survey and orders the work, in either direction |
migrate convert | Converts a SQL dump between MySQL and SQLite |
migrate install | Lands a converted database in a workspace, with a backup |
migrate restore | Puts a backup set back where it came from |
migrate export | Pulls a deployed site's database out |
migrate delta | The second pass of content that changed during a move |
migrate cutover | The checklist a person confirms while traffic switches |
migrate files | Writes the managed files in a dump back onto a filesystem |
🧩 Develop a Module
drangler modify puts a custom module or theme on a live site one revision at a time. Each
revision is stored on the site itself, so sending a one-file change sends one file and a rollback
sends nothing.
1. Link the project to a site. Run it inside the module's directory. It detects the project
shape from the file it names, and writes drangler.json for the project and the owner token to your
user config.
$ cd ~/work/events
$ drangler modify init --site https://my-site.example
detected module-project (/work/events/events.info.yml)
package events
mounts to modules/custom/events
files 24
site https://my-site.example (claimed)
owner token set
2. Check it before anything leaves your machine. Every PHP file is linted with the PHP you name, and paths that would collide on the site are caught here.
$ drangler modify check --php php
package events
mounts to modules/custom/events
files 24 kept, 3 skipped
lint 24 of 24 ok (php 8.4.12)
paths no collision inside this project
3. Upload. Only the files the site does not already hold are sent. The site then boots Drupal with the new code before making it live.
$ drangler modify upload --message "add the event listing"
package events
plan 24 files, 2 not on the site, 22 already there
uploading 2 blob(s), 6.1 kB, 1 batch(es)
commit rev 9f2c1ab4
verify kernel booted
verify kernel booted is the line that matters. If the new code would stop Drupal from booting,
the site restores the previous revision on its own and the command exits 1 naming the error.
4. Turn it on, the first time only:
drangler modify enable events
5. Undo if you need to. The last five revisions stay on the site.
drangler modify revisions # newest first
drangler modify rollback --yes # back to the one before
drangler modify activate 3d81ee07 --yes
| Command | Use it to |
|---|---|
modify status | compare what is live on the site with what is on disk |
modify diff | list the files an upload would send; exits 3 if any |
modify release --tag | upload from a tagged commit, refusing uncommitted edits |
modify list | uploaded packages, and the git repositories the site follows |
modify require <name> | install contrib from drupal.org or Packagist |
modify drop <rev> | delete an old revision and the files only it used |
modify dev | run drangler dev with this project mounted, live-reloading |
Contrib modules come from the registry rather than an upload:
drangler modify require drupal/pathauto drupal/metatag --enable. Pin a version with
--constraint, as in drangler modify require phpmailer/phpmailer --constraint v6.12.0.
☁️ Cloudflare Helpers
| Command | What it does |
|---|---|
cf whoami | Which Cloudflare credential drangler would use |
cf workers | Lists the account's workers against a saved list |
cf versions <worker> | The versions the platform still holds |
cf rollback <worker> <v> | Points a worker back at a version it already holds |
cf secret <worker> … | Lists, sets or removes a secret without printing it |
secrets scan <paths…> | Finds credentials in a dump or a tree, masked |
⚙️ Configuration
| Command | What it does |
|---|---|
config where | Which file supplied each setting |
config check <file> | Scores a wrangler config against known-bad setups |
config levers <file> | The optional features a config declares, and each state |
Settings resolve from a flag, then an environment variable, then a drangler.json in the nearest
parent directory, then your user config. The owner token never goes in drangler.json, which is
committed. site claim stores it in the system keychain, and a machine with no keychain falls back
to your user config with owner-only permissions.
Every command finds the owner token in this order: --token, then DRUPFLARE_OWNER_TOKEN, then the
keychain, then the global config. A token already in the config is not copied into the keychain on
first use; drangler recover-token --store is the explicit way to move one.
Recovering the Owner Token
recover-token proves you can write to the site's Cloudflare account instead of presenting the
token. drangler writes a one-minute, single-use proof into the deployment's CONFIG_KV namespace
through your own wrangler login, then presents it to the site's /recover-token route, which checks
it, spends it and answers with the token. Recovery does not rotate the token, so anything else
holding it keeps working.
- It needs a
wrangler login, orCLOUDFLARE_API_TOKEN, that can edit KV.--accountpicks the account when the login reaches several. - The namespace is
--kv-namespace, else theCONFIG_KVbinding in awrangler.jsoncin the working directory, else the one account namespace withCONFIG_KVin its title. - A new proof can take up to a minute to reach the site. drangler retries with growing pauses, at most eight times, because the site refuses an address after 12 failed attempts in a minute.
--jsonputs the token in theownerTokenfield.- It is not
drangler recover, which reads the 30-day database recovery window.
🚦 Reading the Output
Every command prints a short two-column report on stdout. --json prints the same fields as one JSON object, and progress goes to stderr, so piping a command never mixes the two.
| Exit Code | Meaning |
|---|---|
0 | done |
1 | the check could not run, such as a network failure |
2 | the input was wrong, such as a missing flag |
3 | it ran and found something: a blocker, a secret, a difference |
health gives one verdict:
| Verdict | What it means |
|---|---|
ok | the site answered normally |
warming | a new site unpacking its database, or a page queued to render; wait |
degraded | an error status, or the site is shedding load on purpose to stay in its limits |
unreachable | nothing answered |
not-drupflare | something answered, and it is not a Drupflare site |
Its tier line says what answered: EDGE is Cloudflare's cache in front of the site, HIT is the
site's own stored copy, KV is a copy shared across locations, and RENDER means Drupal built the
page for this request.
✍️ What Writes
build, migrate install, update and preview write to a local workspace; preview --deploy
also creates a Cloudflare Access application and deploys the duplicate as a new worker, which needs
a Cloudflare API token that can edit Access. site, heal, modify,
reconcile --run and sweep --run change a live site, so each needs the owner token, and anything
that changes what visitors see also needs --yes. recover-token writes one record to the site's
CONFIG_KV namespace that expires in a minute, and needs your Cloudflare login instead of the token. Nothing in drangler deletes a file or a directory. The full reference is in the
drangler README.