cf develops, builds, and deploys Workers projects with the same CLI that
manages the rest of your Cloudflare account. To create a project, follow
Deploy your first Worker.
Configure the project with
cloudflare.config.ts. Builds write
Build Output to .cloudflare/output/v0/.
cf does not run a dev server or bundler itself. For cf dev, cf build, and
every other command that builds first, cf hands the work to one of these
tools:
- The framework's own command. When
cfdetects a supported framework, it runs that framework's dev or build command through your package manager. In a Vite project, including a project created withcf init, that isviteorvite build, for examplenpx vite buildwith npm. - An installed Cloudflare build tool. Otherwise,
cfuses the Cloudflare build tool declared in the project'spackage.json. That is the Cloudflare Vite plugin, or Wrangler 4.136.0 or later when the Vite plugin is not declared.
cf uses the Cloudflare Vite plugin 2.0 beta (@cloudflare/vite-plugin@beta),
which does not depend on Wrangler. Wrangler builds projects that declare it
without the Vite plugin, such as projects that cf migrate converts with the
Wrangler bundler and static sites that
automatic configuration sets up. These projects keep
build settings, such as the static assets directory, in a generated
wrangler.config.ts file. That file can change during the beta.
cf does not run your package.json scripts. If your build script runs extra
steps, such as tsc -b && vite build, then cf build and cf deploy skip
them. Chain those steps with cf build in your own script instead:
{
"scripts": {
"build": "tsc -b && cf build"
}
}When cf runs a framework command, it forwards --mode and rejects other
arguments. For example, cf dev --port 8788 fails in a Vite project. Set the
option in the framework's configuration, such as server.port in
vite.config.ts, or run the framework command directly. When cf uses an
installed build tool instead, cf dev forwards extra arguments to it, and the
tool rejects arguments it does not support. cf build accepts only --mode.
When a project has no cloudflare.config.ts, cf tries to detect its
framework and set the project up for Cloudflare before it continues. This
automatic configuration runs from these commands:
cf devandcf buildcf deploy, includingcf deploy --dry-runcf previews deploycf workers versions create,cf workers triggers deploy, andcf workers checkcf init
A project counts as configured only when cloudflare.config.ts exists in the
directory where you run the command. Passing --prebuilt skips automatic
configuration.
In a terminal, cf shows the planned changes and asks before it applies them.
Without a terminal, or in CI, it applies the changes and installs packages
without asking. Run cf init . locally before you set up CI. It configures an
existing project without building it. Review the changes and commit them. For
the list of changes, refer to
Start from an existing project.
Start the project's development server:
cf devThe dev server prints its local URL.
Build the project:
cf buildAfter the build finishes, cf reads and validates .cloudflare/output/v0/.
cf build does not upload anything and does not need credentials.
cf deploy builds the project, validates Build Output, resolves your
credentials and account, uploads a new Worker Version, and deploys it:
cf deploySign in with cf auth login, or set CLOUDFLARE_API_TOKEN, before you deploy.
For details, refer to Sign in.
cf deploy can provision missing resources for bindings that omit resource
identifiers. It does not write provisioned identifiers back to
cloudflare.config.ts.
cf deploy accepts these options:
| Option | Purpose |
|---|---|
--dry-run |
Builds and validates the Worker without uploading it |
--message <TEXT> |
Records a message on the Worker Version |
--tag <TAG> |
Records a tag on the Worker Version |
--secrets-file <PATH> |
Uploads secrets from a JSON or .env format file with the version |
--dispatch-namespace <NAMESPACE> |
Deploys a Workers for Platforms user Worker to that dispatch namespace |
--containers-rollout <STRATEGY> |
Sets the Container rollout strategy: immediate, gradual, or none |
--worker <NAME> |
Selects a Worker from Build Output instead of the default Worker |
--prebuilt |
Deploys existing Build Output without building |
--dry-run sends no API requests and needs no credentials, so you can validate
a project before you sign in. In a project without cloudflare.config.ts, it
still runs automatic configuration first, which can install packages and change
files.
cf deploy --dry-run
cf deploy --message "Fix header parsing" --tag v1.2.0A mode selects which configuration a function-form cloudflare.config.ts
returns. Pass it with --mode or -m:
cf dev --mode staging
cf build -m staging
cf deploy --mode stagingWhen you omit --mode, the Cloudflare Vite plugin uses development for
cf dev and production for builds. Builds through Wrangler and API commands
leave the mode undefined. For the full list, refer to
Select a mode.
When cf runs a framework's own command, only Vite and Astro accept --mode.
Other framework commands fail with an error. Refer to
A framework rejects --mode.
This configuration deploys a separate staging Worker with its own API origin:
Select a highlighted line to show its type and description below it.
export default defineConfig(({ mode }) => { (defineConfig, mode reference)
defineConfigFunctionLink to defineConfig
defineConfig<T extends ConfigInput<CloudflareConfig>>(config: T): T;Defines the default export of cloudflare.config.ts. Pass a configuration object, a promise that resolves to one, or a function that receives the config context (isPreview and mode) and returns either.
modeContext valueLink to mode
mode: string | undefinedThe mode the config is being evaluated in. Set via the --mode CLI flag. In Vite the mode defaults to development in vite dev and production in vite build (more info). In Wrangler the mode defaults to undefined.
worker: { (worker reference)
workerOptionalLink to worker
worker?: ConfigInput<WorkerConfig>The Worker defined by this configuration.
name: isStaging ? "example-worker-staging" : "example-worker", (name reference)
entrypoint, (entrypoint reference)
entrypointOptionalLink to entrypoint
entrypoint?: string | WorkerModuleThe entrypoint module that will be executed. May be either a path string (e.g. "./src/index.ts") or a module namespace imported with the cf-worker import attribute.
compatibilityDate: "<COMPATIBILITY_DATE>", (compatibilityDate reference)
compatibilityDateRequiredLink to compatibilityDate
compatibilityDate: stringA date in the form yyyy-mm-dd, which will be used to determine which version of the Workers runtime is used. More details at https://developers.cloudflare.com/workers/configuration/compatibility-dates
env: { (env reference)
envOptionalLink to env
env?: Record<string, Binding>Bindings exposed on the Worker's env object. Construct entries with bindings.kv(...), bindings.r2(...), etc.
API_ORIGIN: bindings.text( (text reference)
textBuilderLink to text
text<T$1 extends string>(value: T$1): TextBinding<T$1>;Inline string value made available to the Worker on env under the binding name. For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
Return one complete configuration for each mode. Programmatic configuration
does not merge environment blocks the way Wrangler environments do. A mode
deploys a separate Worker only when it returns a different name.
Build Output records the mode it was built with. When you deploy an existing build, pass the same mode.
Pass --prebuilt to deploy an existing .cloudflare/output/v0/ directory
without building. One CI job can build, and another can deploy the restored
directory. --prebuilt also skips automatic configuration.
The deploy command must request the mode that Build Output records:
- When Build Output records a mode, pass exactly that mode with
--mode. - When Build Output records no mode, do not pass
--mode.
Vite builds always record a mode. cf build without --mode records
production, so deploy that build with --mode production:
cf build
cf deploy --prebuilt --mode productionDeploy a staging build with the staging mode:
cf build --mode staging
cf deploy --prebuilt --mode stagingBuilds through Wrangler record a mode only when you pass --mode to
cf build. To check the recorded mode, read buildContext.mode in
.cloudflare/output/v0/config.json.
The same rule applies to --prebuilt with cf previews deploy,
cf workers versions create, cf workers triggers deploy, and
cf workers check. When the modes do not match, the command stops before it
uploads anything and prints the --mode value to use.
For a complete pipeline, refer to Use cf in CI.
Upload a Worker Version without deploying it:
cf workers versions createThis command builds and validates the project the same way as cf deploy. It
accepts --prebuilt, --mode, --message, --tag, --secrets-file,
--dry-run, and --worker. Use --preview-alias <ALIAS> to give the version
a preview URL alias.
To send traffic to an uploaded version, create a deployment:
cf workers deployments create --worker example-worker --strategy percentage --versions '[{"version_id":"<VERSION_ID>","percentage":100}]'Apply trigger configuration from Build Output without uploading a new version:
cf workers triggers deployThis command applies routes, custom domains, the workers.dev setting, cron
schedules, Queue consumers, and Workflows. It builds the project unless you pass
--prebuilt. It also accepts --mode, --worker, and --dry-run. A dry run
sends no API requests.
Deploy the project as a Worker Preview:
cf previews deployThe command builds the project with isPreview set to true, so a
function-form cloudflare.config.ts can return preview-specific settings. It
then uploads the preview and prints the result as JSON. Previews in cf can
change during the beta.
The preview name defaults to the current branch. cf reads the branch from
Workers Builds, GitHub Actions, or GitLab CI/CD, and then from Git. On a
detached HEAD with no CI branch, pass a name:
cf previews deploy my-featureThe command accepts --mode, --worker, and --prebuilt. With --prebuilt,
Build Output must come from a preview build, and the
mode rule applies. There is no --dry-run, and the
command needs credentials.
The JSON result contains type, version, preview_id, preview_name,
preview_slug, preview_urls, deployment_id, and deployment_urls.
Previews do not support Durable Object-managed Containers. cf deploy,
cf workers versions create, and cf workers triggers deploy refuse preview
Build Output and print the cf previews deploy command to use instead.
Profile the Worker's startup performance locally:
cf workers checkThe command builds the project unless you pass --prebuilt. It prints the
bundle size and startup timings as JSON, and writes a CPU profile to
worker-startup.cpuprofile. Use --outfile <PATH> to choose a different file.
The command also accepts --mode and --worker.
The measurement runs on your machine. Use it to find where startup time goes, not to predict startup time on Cloudflare.
Generate TypeScript types from cloudflare.config.ts:
cf workers typesThe command writes .cloudflare/types/index.d.ts, which contains the Env
binding types and the Workers runtime types. Pass --no-include-runtime to
leave out the runtime types, or --mode to evaluate the configuration for a
named mode.
The Cloudflare Vite plugin writes the same file during development and builds.
Run cf workers types in projects that build through Wrangler, or before tsc
in a type-check script. Projects created with cf init include a typecheck
script that runs cf workers types && tsc.
Add --local to a supported command to run it against a local simulation
instead of the Cloudflare API:
cf d1 raw <DATABASE_ID> --sql "SELECT 1" --local
cf r2 objects list --bucket-name <BUCKET_NAME> --local--local works only for a few resources that local development provides.
cf starts a short-lived local runtime for each command, so no dev server
needs to be running. Local support covers these commands:
cf kv keys get,cf kv keys list,cf kv keys put, andcf kv keys deletecf kv bulk get,cf kv bulk put, andcf kv bulk deletecf d1 rawcf d1 migrations listandcf d1 migrations applycf r2 objects get,cf r2 objects put,cf r2 objects list, andcf r2 objects bulk-deletecf d1 list,cf kv namespaces list, andcf r2 buckets list
cf d1 query has no local equivalent. Use cf d1 raw instead. A command
without a local equivalent fails with
This command has no local equivalent. instead of calling the Cloudflare API.
By default, --local keeps its data in a state/v3 directory inside the cf
configuration directory. That is ~/.config/cloudflare/state/v3 on Linux and
~/Library/Preferences/cloudflare/state/v3 on macOS. Every project on your
machine shares this directory. Pass --persist-to <DIRECTORY> to use
<DIRECTORY>/v3 instead. --persist-to works only with --local.
This is not the data your dev server uses. The Cloudflare Vite plugin 2.0 beta
keeps development data in the project, under .cloudflare/state/.
Project commands, such as cf dev, cf build, and cf deploy, run a build
tool that loads the whole cloudflare.config.ts, including the Worker and
Containers.
Ordinary API commands, such as cf d1 list, read only accountId and
complianceRegion from the nearest cloudflare.config.ts in the current
directory or a parent directory. A syntax error, import error, or top-level
runtime error in that file still stops them. For details, refer to
Set account defaults.
API credentials, such as CLOUDFLARE_API_TOKEN, can also come from a .env
file in the current directory. Commands that build first, such as cf deploy,
load those values after the build finishes. For details, refer to
Load credentials from a .env file.
No Cloudflare dev-server is installed in this project.cf found no framework that it recognizes and no Cloudflare build tool
declared in package.json, for example in an empty directory. To create a
project, run cf init.
In a configured project whose dependencies are not installed, Vite reports that
it cannot resolve @cloudflare/vite-plugin, or cf reports that a build tool
is declared but not installed. Install dependencies with your package manager,
then run the command again.
Arguments cannot currently be forwarded to the detected dev command `npx vite`. Run that command directly with the required arguments.cf runs the framework's command and forwards only --mode. Set the option in
the framework's configuration, or run the framework command directly.
The detected command `<COMMAND>` does not currently support `--mode`.Only Vite and Astro accept --mode when cf runs a framework command. Run the
command without --mode.
The Build Output was created with mode "production", but this command did not specify a mode. Rerun with "--mode production".The Build Output does not record which mode it was created with, but this command requested mode "staging". Rebuild with "--mode staging" before deploying.Pass exactly the mode that Build Output records, or omit --mode when it
records none. Refer to Deploy a prebuilt build.
Build Output Specification: no root config found at <PATH>/.cloudflare/output/v0/config.json.A --prebuilt command found no build. Run cf build first, or restore the
complete .cloudflare/output/v0/ directory from your build job.
This build output is for a Preview. Run cf previews deploy --prebuilt --mode production instead.The existing Build Output came from cf previews deploy. Run the suggested
command to deploy the preview, or run cf build to create production output.
We couldn't determine a Preview name from CI or Git.cf previews deploy found no branch name, for example on a detached HEAD.
Pass a name: cf previews deploy <PREVIEW_NAME>.
This command has no local equivalent. Re-run without --local to use the Cloudflare API.The command does not support --local. For D1 queries, use cf d1 raw instead
of cf d1 query. Otherwise, run the command without --local.