Publish to Cloudflare Pages
The Publish panel connects your project to Cloudflare Pages, so that every change you publish builds and goes live automatically. Cloudflare Pages is a free host that serves your prebuilt pages from a CDN, and if your project has a database or sign-ins, it also runs the small worker Jx emits for their
/_jx/*
routes. Open it from
Publish › Hosting
: the host section's
Set Up Publishing
button, which is also the
Set Up Publishing
command in
Quick Access
.

Before you start, the project needs to live on GitHub. If it doesn't yet, GitHub walks you through publishing it from Studio.
Connect your Cloudflare account
The first time you open the panel, it asks for a Cloudflare connection. What you see depends on your Studio platform:
Connect Cloudflare : click it and sign in to Cloudflare in the window that opens. Done.
API token form : some platforms ask you to paste a Cloudflare API token instead. Create one in the Cloudflare dashboard with the permissions the panel names (Account Settings Read, Pages Read/Write), then click Verify & Connect . The token stays on your machine.
Once a token is stored, the panel reports that it is stored. It never renders the token back into the field. The box is drawn empty, and only when you ask to replace the token. Revoking lives with every other credential, in Preferences › Accounts .
If the panel instead says it can't reach the Cloudflare API on this platform, you don't need it at all. Set up Pages once in Cloudflare's own dashboard and publishing still works the same way: publish your changes, and your host builds.
Where the platform holds the connection for you, an authorization that has expired is named as exactly that: the panel says the connection expired and offers Reconnect Cloudflare , rather than asking you to connect an account you already connected. Your deployments are untouched. The site keeps serving, and only the panel's ability to read and change the Pages project is waiting on the reconnection.
A hosted Studio may need something from you before it publishes. If so, the step that was refused says why, and Studio offers what the platform offers. Once that is done, run the step again.
Create and connect a Pages project
Once connected, the panel offers to create a Pages project tied to your repository:
Account : pick your Cloudflare account.
Pages project name : pre-filled from your project's name; this becomes part of your free site address.
GitHub owner and GitHub repository : where the project lives.
Production branch : the branch that publishes to your live site, normally
main.Click Create & Connect .
Studio creates the Pages project (or reuses one with that name if it already exists) and configures it to build and publish your site on every push. If Cloudflare reports it can't see the repository, the error includes a link to install the Cloudflare Pages GitHub App. Install it on the repository and try again.
Watch deployments
After connecting, the panel becomes a status view:
The connected Pages project's name, with a link to your live site address.
The latest deployment's stage and status (for example deploy: success ), with a preview link to that exact build.
Refresh re-checks; Disconnect removes the connection (your Pages project and site stay up; only the link from Studio is removed).
There is no publish button here, because publishing is automatic: once a provider is connected, Publish live in Review changes commits, pushes and asks Cloudflare what it built. Right after connecting, the panel shows No deployments yet . Your next publish starts the first one.
Publish › Deploys follows it from then on: the live address and the latest production deployment, a deploy that is running with its steps, every deployment Cloudflare reports, and the branch previews, the deployments built from a branch other than production. Each row says its state in words: Live for the production deployment serving the site, Replaced for an older one, Ready for a finished preview, and Building… , Failed or Canceled otherwise; hover the word for the stage and status Cloudflare reported. The list is read when you open Deploys, when you click its Refresh , and again after a deploy finishes.
Sites with a database or sign-in
Pages serves both halves of a Jx site, but a project with data tables or accounts needs three things arranged once:
Set the adapter. Set
build.adapterinproject.jsontocloudflare-pages, or tocloudflare-workersif you deploy the site as a Worker instead: pick it under How it is built in Publish › Hosting . Connecting this panel doesn't change the adapter for you, and the build stops with an error on Static as soon as the project declares data tables.Push the schema to the real database, from a terminal. While you develop, a D1 connection is stood in by a local SQLite file. Studio's Push Schema button goes through that same local backend, so it creates your tables in
.jx/data/<connection>.sqliteand never touches D1 orwrangler.jsonc.jx db pushis the path that talks to the connection as declared: it applies the same additive plan to D1 itself, and writes D1's binding into your project'swrangler.jsoncon the way through. Reaching D1 from outside a deployed worker goes over Cloudflare's API, which needs three things together: the connection's database ID , aCLOUDFLARE_API_TOKEN, and an account ID (the connection's own account ID , orCLOUDFLARE_ACCOUNT_ID). Miss one and the push reports the connection as unreachable. Accounts need a second pass: the auth extension's own tables aren't part of the CLI push, and Auth and secrets covers where they come from.Set the secret values on Cloudflare.
project.jsonrecords only the names of environment variables: the session signing secret, a database URL, OAuth credentials. Give each name a value on the Pages project, withwrangler pages secret put <NAME>or the environment settings in Cloudflare's dashboard; locally the same names are read from.dev.vars. Auth and secrets covers the whole arrangement.
Your pages stay prerendered and CDN-served either way, because only the
/_jx/*
routes reach the worker. The two adapters arrange that differently:
Cloudflare Pages
ships a
_routes.json
alongside the worker that tells Cloudflare to wake it for
/_jx/*
and nothing else, while a
Cloudflare Workers
deploy puts the worker in front of every request and hands anything that isn't one of its routes straight to the static assets.
Studio records the connection under
build.deploy
in
project.json
(provider, account, project name, and live address), so it travels with the repository, and any copy of Studio that opens the project knows publishing is already set up. Cloudflare builds with
bunx jx build
and serves the
dist/
output. For a project that lives in a subfolder of its repository (opened on Jx Cloud from that folder), the Pages project Studio creates builds in that folder, so the same command builds that project and nothing beside it.
Next
Source control is the commit-and-sync flow that triggers each deployment.
Other hosts puts the same site on Netlify, GitHub Pages, or anywhere else.
packages/studio/src/surfaces/publish.ts