Updating
Charcha updates by pushing to your own copy of the repository. Cloudflare rebuilds the same Worker, on the same address, against the same database, and your comments and settings carry on as they were.
The part worth reading first is what not to do.
Do not press the Deploy button again
Section titled “Do not press the Deploy button again”The Deploy button is a first-run tool. Pressing it a second time does not update anything. It builds a second everything: a new repository, a new Worker on a new address, and a new build pipeline pointing at the new repository.
Choosing your existing database on the form does not save you. The comments come along. The Worker serving them does not.
What makes this expensive is that nothing appears to break. Your site still works, because the embed on your pages still points at the old Worker. Meanwhile the new one has:
- no dashboard password, no
IP_HASH_SECRET, no Turnstile key, because secrets belong to a Worker rather than to a repository and were never in the code - no allowed origins, if you also let it make a fresh database, so it would turn your own site away
- its own build pipeline, so the old Worker is the one still serving your readers and the new one is the one getting your updates
You find out when you repoint your embed at the new address and the dashboard refuses to let you in.
If you have already done this, nothing is lost. Delete the second Worker and its repository, and carry on updating the first one as below. Your comments were never in the Worker.
The one-time setup
Section titled “The one-time setup”When you deployed, Cloudflare cloned Charcha into your account rather than forking it. A clone has no link back to where it came from, so there is no “sync fork” button on your repository and nothing to pull from yet. You add that link once, by hand.
Run this once, replacing the first URL with your own repository’s. The last three lines are what stop wrangler.jsonc conflicting on every update, and the next section explains why.
git clone https://github.com/YOUR-ACCOUNT/YOUR-REPOSITORY.git charchacd charchagit remote add upstream https://github.com/withsetu/charcha.gitgit config merge.keepmine.driver trueprintf 'wrangler.jsonc merge=keepmine\n' >> .gitattributesgit add .gitattributesgit commit -m "Keep this deployment's settings across upstream merges"git pushThat is the whole of the setup, and you never do it again.
One line of it lives on your machine rather than in the repository. git config merge.keepmine.driver true is what teaches git what keepmine means, and git deliberately refuses to let a repository define that for whoever clones it. If you ever move to another computer, or clone this repository again, run that one line there too. Without it git reports an unknown merge driver and falls back to a normal merge, which is the conflict you were avoiding rather than anything broken.
The first merge, which is the awkward one
Section titled “The first merge, which is the awkward one”Your first merge needs a flag that no later one does:
git fetch upstreamgit merge upstream/main --allow-unrelated-historiesWithout it git stops with fatal: refusing to merge unrelated histories, and that is not a sign anything is wrong. Cloudflare cloned Charcha into a brand new repository with its own first commit, so as far as git is concerned your copy and ours are two unrelated projects that happen to contain the same files. The flag says you know that and want them joined anyway. It is needed once, because after this merge they share history.
Expect conflicts on this first merge, and expect them to be dull. With no shared ancestor, git cannot tell which side changed a file, so every file that differs at all is handed to you. How many that is depends only on how far behind you are: a copy deployed this morning may conflict on two or three files, one from months ago on many more.
The resolution is the same for all of them. Take ours for everything except wrangler.jsonc, which is yours and which the setup above already keeps for you:
git checkout --theirs path/to/each/conflicted/filegit add -Agit commit --no-editgit pushgit status lists the conflicted paths, and git checkout --theirs accepts several at once.
Then open wrangler.jsonc and confirm your own database_id is still in it before you trust the deploy. If it is, the setup worked and you will not have to look at that file again.
Every update after that
Section titled “Every update after that”git fetch upstreamgit merge upstream/maingit pushNo flag, and normally no conflict. Git knows what you already have, so it only brings what changed.
Pushing is what deploys. Cloudflare’s build pipeline watches your production branch, and a push to it rebuilds and redeploys the same Worker. There is no button to press afterwards and nothing to redeploy by hand.
Migrations ride along. The deploy script applies any new ones to your database before it deploys the new code, so a version that needs a schema change brings its own.
The conflict the setup above prevents
Section titled “The conflict the setup above prevents”Once the first merge is behind you, wrangler.jsonc is the only file that can conflict again, and without the setup above it would do so on any update that touches it.
When Cloudflare set your deployment up, it wrote your details into that file: your database’s id and name, and your Worker’s name if you changed it on the form. That is the only place your repository differs from ours by design rather than by being out of date, which is why one rule handles it.
merge=keepmine is that rule. It tells git to keep your version of that one file whenever an update touches it, so your database id survives every merge without you looking at it. Nothing else is affected, because the attribute names one file.
The trade is worth stating plainly. Keeping your file means you also keep our old version of everything else in it, so a release that adds a binding or moves the compatibility date does not reach you automatically. Those are rare, and a release that needs one says so in its notes. When it does, open wrangler.jsonc, copy the new entry across by hand, and leave your database id where it is. The comments in that file say what each entry is for.
If you skipped the setup and are looking at a conflict now:
- Keep yours for
database_id,database_nameandname. Those point at your resources. Taking ours would aim your Worker at a database that does not exist, because the copy in this repository is a placeholder. - Take ours for everything else.
Checking it worked
Section titled “Checking it worked”Your Worker’s build log is in the Cloudflare dashboard, under your Worker, in Deployments. A successful build ends with the deploy step and the new version becomes active straight away.
Two things are worth looking at in that log rather than assuming:
The migration step. It runs before the deploy. If your build’s token was created without permission to touch D1, this step fails with a non-zero exit and very little explanation, which is a known rough edge in Cloudflare’s tooling rather than anything about your database. The tell is a build that fails before it ever reaches the deploy step. Applying the migration yourself from a terminal and pushing again gets you moving.
The pnpm version. Charcha’s lockfile needs pnpm 10. If Cloudflare’s build image moves to a newer major, pnpm prints Ignoring not compatible lockfile and then installs a dependency tree nobody tested rather than stopping. The build goes green. If an update behaves strangely and that line is in the log, set PNPM_VERSION to 10.11.1 as a build variable in your Worker’s settings.
Afterwards, /health on your Worker answers 200 with {"status":"ok","database":"ok"} when the Worker is running and its database has been migrated. It is the fastest check that an update landed cleanly.
What survives an update
Section titled “What survives an update”Everything you configured:
| Thing | Where it lives | Survives |
|---|---|---|
| Comments | your D1 database | yes |
| Allowed origins, moderation policy | the settings table in that database |
yes |
| Every secret | the Worker, set separately from the code | yes |
| What the spam classifier learned | the spam_model table |
yes |
| Your Worker’s address | unchanged, because it is the same Worker | yes |
Nothing on that list is in the repository, which is why pushing new code cannot disturb any of it. Your embed tag does not change, and neither does anything on your site.
Going back
Section titled “Going back”Cloudflare keeps your Worker’s last 100 versions. In the dashboard, go to your Worker, then Deployments, then the three-dot menu beside the version you want and Rollback. It takes effect immediately.
Rolling back the code does not roll back your database, and Cloudflare says as much in its own warning on the feature: resources connected to your Worker are left alone, and errors can follow if the shape of the data changed between the two versions.
For Charcha that means a rollback across a migration is not a clean undo. The schema change stays. Migrations here are written to add rather than to remove, so an older Worker usually runs against a newer database, but “usually” is doing real work in that sentence and it is worth reading what the migration actually did first. Rolling back a version that changed no schema is uneventful.