Deployment, resources, and domains
Recover from the stage where deployment failed and check Cloudflare resources, environment variables, domains, and production content.
Deployment is not a single transaction. A script failing at the end does not mean earlier remote operations never happened. Before troubleshooting, record the first error, failed stage, code version, and time, then confirm the current production state.
1. Choose the right project and command
| Scenario | Command |
|---|---|
| Create the remote Worker and resources for a new project's first deployment | npm run deploy:init |
| Publish subsequent changes when a Worker and complete remote bindings already exist | npm run deploy:update |
| Attach or change the production domain | npm run domain:set -- https://app.example.com |
These commands belong to the initialized application project. The default template has no deploy:prod command or production environment configuration that requires wrangler --env production. .env.production is the variable file read by deployment scripts, not a named Wrangler environment.
The presence of account_id alone does not prove that the first deployment completed. This field may be written before resources are created. Check the Worker and resources as well.
2. Confirm account and resource ownership
npx wrangler whoami
npm run doctor:remoteCheck that the current identity can access wrangler.jsonc.account_id and that the configured Worker, D1 IDs, KV IDs, R2 names, and Queue names belong to the intended project.
doctor:remote primarily checks local production configuration, resource identifiers and naming relationships, and account access. It does not individually verify the existence of every remote D1, KV, R2, and Queue resource or run complete workflow tests. If a resource is missing, check the actual resources in the corresponding account's dashboard.
Names created by the CLI usually have a project-name prefix, such as my-app-db. Do not assume that a remote resource must use the template's default name, or copy another application's database ID just to pass the checks.
3. The first deployment fails partway through
Identify where deployment stopped before choosing a recovery method:
| Failed stage | What may already be complete | Next step |
|---|---|---|
| Configuration prompts or resource prechecks | Local configuration and .env.production may have changed | Fix the configuration and confirm that no remote resources were created before running the first deployment again |
| Type checking or build | Some local files have changed, but the Worker may not yet be deployed | Fix the first code or content error |
| Resource creation or Worker upload | Some remote resources may exist | Check each resource against the configuration instead of blindly creating resources again |
| Remote database initialization | The Worker may be live, and one database may be initialized | Follow the database chapter to check both databases |
| KV synchronization | The Worker and databases may be ready | Resume synchronization using content from the same version |
| Page health checks | Deployment may already be complete | Inspect production responses and Worker logs directly |
The first deployment publishes the Worker before preparing databases and content. Open the application to traffic only after all these steps succeed.
If the Worker and bindings such as D1 and KV are complete, you can use the update flow to finish the release after fixing the failure. If only some resources were created, confirm their ownership and whether they contain data, then fix the missing configuration. Do not delete same-named resources or clear IDs to force a fresh start.
See First deployment and subsequent updates for the full flow.
4. Identify where an update deployment stopped
The main stages of the current deploy:update are:
Verify the account, Worker, production environment file, master secret, and site URL
→ doctor:remote → cf-typegen → verify
→ db:migrate:remote → Deploy the Worker
→ kv:sync:remote → Run page health checksIf verify fails, the current update has not yet run the subsequent remote migrations or deployment. Fix the code, types, tests, or build first. Do not skip verification and deploy directly.
If remote migration fails, some earlier migrations may already have completed. If Worker upload fails, the database may already be updated. Ensure the old Worker can still use the current schema. Rolling back code does not also restore the database.
If KV synchronization or health checks fail, the new Worker may already be live. Check the deployed version and actual responses before deciding whether to rerun the update or fix a specific stage.
5. Environment files are correct, but production reports missing configuration
Check which file and Worker you are inspecting and whether deployment followed the change:
| Changed content | Required follow-up |
|---|---|
.env | Restart local development and verify the change. Production is not updated automatically |
.env.production | Run an update deployment to load the variables into the Worker |
config/ or UI translation resources | Rebuild and deploy |
| OAuth or Turnstile platform settings | Save the settings on the platform and verify them again. Deploy as well if application credentials changed |
Deployment scripts distinguish ordinary variables from secrets. Variables starting with VITE_ may be included in browser build artifacts and must not contain secrets.
Empty strings are not written to the remote Worker as new values. Remote secrets omitted from the file are not automatically deleted either. To disable an old integration, explicitly handle its configuration and remote secrets according to how the service is used. Simply emptying the file values is not enough.
For SAAS_SECRET must exist and match, check that .env and .env.production still use the project's original master secret. Do not generate a new value in both files merely to make them match. Existing data may become impossible to decrypt.
The token used for Cloudflare deployment is a tooling credential. Do not put it in the application's .env.production. The current scripts reject these fields.
6. Binding or Durable Object errors
First determine whether the error occurs during type checking or at runtime:
- For missing types, check
wrangler.jsonc, then runnpm run cf-typegen. - For a missing binding at runtime, inspect the deployed version and actual bindings. Generating types does not create remote resources.
- If Queue messages are not processed, follow Background jobs and analytics to check the three names and the consumer.
- For Durable Object errors, compare
class_namewith the class names actually exported bysrc/index.tsxand inspect migration declarations.
The current template exports RateLimiterDO, CounterDO, NonceDO, TokenBucketDO, and TimerDO. Follow Durable Object migration rules when adding or changing classes. Do not arbitrarily change migration tags that have already been deployed. See Wrangler Durable Object configuration.
7. The domain is unreachable or redirects repeatedly
Inspect the redirect chain in the browser's Network panel first. Determine whether the failure is in DNS, TLS, the site entry point, or the sign-in flow.
| Symptom | What to check |
|---|---|
| Domain resolution or connection fails | DNS, target account, domain setup, and certificate status |
| Redirect loop between domains | VITE_SITE_URL, actual host, deploy.hosts, and proxy redirect rules |
| Home page works, but sign-in stops working | Cookie host, protocol, and OAuth callback |
| Only an old entry point fails | Whether it still points to an old Worker or custom domain |
The template requires a full HTTPS origin for the production URL, without an additional path, query parameters, or port. Use domain:set to set the production domain. It changes configuration and redeploys, but does not run the full database migration and KV synchronization steps of a routine update.
After switching domains, check GitHub, Google, Stripe, and Turnstile configuration separately. Changing the site URL does not automatically update callbacks or allowed-host lists on third-party platforms.
8. Deployment completed, but content is still outdated
Confirm the URL you are visiting and the Worker version before investigating caches. For documentation and blog content, inspect page navigation, body content, and the search index separately.
If generated navigation or search content is updated but remote KV synchronization fails, page structure may be new while the body remains outdated. After confirming that local code matches the current release, you can resume content synchronization on its own:
npm run kv:sync:remoteThis writes to remote storage. Use the correct content version intended for release. Normal releases usually use deploy:update to update both build artifacts and KV, so there is no need to repeat synchronization manually every time.
If /docs or /blog returns 404, also check the corresponding deploy.content switch, baseUrl, enabled languages, and content directories. Do not treat every 404 as a CDN cache issue.
9. Inspect logs and verify recovery
Start live logs from the target project directory, then reproduce the failed request once:
npx wrangler tailYou can also view the target Worker's runtime logs in the Cloudflare dashboard. Record the failed path, time, error name, and correlation ID. Redact credentials and personal information before sharing. See Wrangler Worker commands for command details.
Health checks only inspect responses from pages such as the home page and enabled content entry points. They do not prove that signup, payments, email, or background jobs work. After fixing the issue, repeat the failed operation, then follow Launch verification to check the affected workflows.