How to deploy an existing project with Codex Sites
A practical guide to hosting a project you already have with Codex Sites: the compatibility check, the deploy prompt, hosting.json, and the save-deploy loop.
If you already have a project and you want Codex Sites to host it, the path is short but specific. Codex Sites hosts builds that produce Cloudflare Worker-compatible output as ES modules, so the first real question is not "how do I deploy" but "will this even run on Sites." You ask Codex to confirm compatibility, you let it make any required changes, then you save a reviewable version and deploy that. This post walks the whole loop — the one-line deploy prompt, what .openai/hosting.json records, how to wire in storage and secrets, and the save-review-deploy gate — and stays honest about the fact that Codex Sites is still in preview.
Will your project even run on Sites?
Codex Sites is not a general-purpose host. It hosts projects whose build produces Cloudflare Worker-compatible output as ES modules. For a brand-new project, the recommended Sites starter already builds to that target, so you rarely think about it. For an existing project, this is the thing that decides whether the deploy is mechanical or a small migration.
So before you ask for a deployment, ask for a verdict. The information-gain move here is to make compatibility an explicit step rather than discovering it mid-deploy. Have Codex inspect the build and confirm it can emit compatible artifacts — and if it cannot, have it tell you exactly what would need to change. Frameworks that can target a Workers-style runtime are the easy cases; anything that assumes a long-running Node server, native binaries, or a filesystem it can write to at runtime is where you should expect changes.
A quick way to sort your own project before you start:
| Signal in your project | Likely on Sites? | What to do |
|---|---|---|
| Already builds to a Workers / edge target | Yes, mostly mechanical | Confirm artifacts, then deploy |
| Static output plus light server logic | Usually, with small changes | Ask Codex what to adjust |
| Long-running Node server or background workers | Needs changes | Ask Codex for a compatible build path |
| Writes to local disk at runtime | Needs changes | Move persistence to D1 or R2 |
The point is to learn this before you spend a deploy on it, not after.
The one-line deploy prompt
Once you have a project open in Codex, the deploy itself is a single instruction. Name the plugin with @Sites so Codex treats this as a hosting job rather than generic code generation, and ask it to check compatibility as part of the same request:
@Sites Deploy this project. Check whether it is compatible with Sites, make any required changes, and give me the deployment URL.
That prompt does three things in order: it checks the build against what Sites can host, it applies any required changes, and it returns a URL. Because every deployment URL on Codex Sites is a production URL, treat this as a real publish — which is exactly why we lean on the save-and-review step below before sending the link anywhere.
What .openai/hosting.json records
A Codex Sites project is the link between your local source and the hosting Codex manages on OpenAI's side. That linkage lives in a small file at .openai/hosting.json, alongside the names of any storage bindings the app uses.
A new starter can begin with no project_id at all — Sites fills it in once it provisions the project. After provisioning, a minimal file that wires up a relational database and no object storage looks like this:
{ "project_id": "<project-id>", "d1": "DB", "r2": null }
Read that as three facts: which hosted project this source is linked to (project_id), the binding name for a relational database (d1), and the binding name for object storage (r2, here left null because this app does not store files). What is deliberately not in this file: secrets. Those go elsewhere, which is the next section.
Add storage and secrets if you need them
Reach for storage only when product data has to survive between visits — not for temporary UI state, which does not need a database at all. Codex Sites offers two kinds, and you can use either or both:
- D1 — a relational database for durable, structured data.
- R2 — object storage for files.
- D1 + R2 — files plus searchable metadata about them.
If your existing app already had a database, expect Codex to map that need onto D1 (or R2 for blobs) as part of making the project compatible. Ask it to show you the migrations in the review pane before you publish them.
Secrets and environment variables are set in the Sites panel, never committed to the repo and never written into .openai/hosting.json. The discipline that keeps this sane on an existing project: keep your local .env and .env.example aligned with the keys the app actually needs, so the list of names is version-controlled even though the values are not. One thing that surprises people: changing a hosted env value does not redeploy on its own. After you update a secret in the panel, ask Codex to redeploy the approved saved version so the live site picks it up.
Save, review, deploy
Codex Sites splits shipping into two stages on purpose, and on an existing project that gap is your safety net. Save builds a reviewable candidate tied to your current Git commit; nothing goes live. Deploy publishes a saved version and returns the production URL.
| Stage | What it does | Live? |
|---|---|---|
| Save | Builds a candidate tied to the source commit | No |
| Deploy | Publishes an approved saved version | Yes — production URL |
The loop for an existing project: confirm compatibility, let Codex make changes, save a version, open the Codex review pane to read the source changes and any database migrations, then deploy the version you approved. The review pane is where you catch a migration you did not expect or a change that does more than you wanted — read it before you share the URL, not after.
Common reasons a deploy needs changes
Most existing projects need at least a small nudge. The usual culprits:
- The build does not emit Worker-compatible ES modules yet — the headline compatibility issue.
- The app assumes a writable local filesystem; persistence has to move to D1 or R2.
- Required environment variables are not set in the Sites panel, so the running app is missing config.
- It relies on a long-running server process or native dependencies that do not fit the runtime.
None of these are dead ends — they are just the list of things Codex tends to fix when you ask it to "make any required changes." Knowing them in advance means you read its proposed diff with the right suspicions.
Where this fits
The deploy is the easy half. The hard half is the brief — knowing exactly what you are shipping and why — and that is the part Codex Sites does not do for you. Before we type @Sites, we draft and pressure-test the plan in a multi-model chat: we use oran.chat to run the same spec past GPT, Claude, and Gemini and branch the prompt instead of overwriting it, so the brief we hand Codex is the one that survived three sets of objections. If you want one instruction set to hold across those models, see the system prompt that works across GPT, Claude, and Gemini.
For the surrounding steps, our step-by-step Codex Sites tutorial covers the end-to-end flow from a prompt, Codex Sites database and storage goes deeper on D1 and R2, and save vs deploy in Codex Sites digs into the review gate. The authoritative reference is the Codex Sites documentation. For more like this, see Playbooks.