This guide creates a Worker with cf init, runs it on your
machine, and deploys it to your Cloudflare account.
Install cf and check the
requirements. You do not need to sign in until
you deploy.
Create a project in a new directory:
cf init my-workercf init asks which package manager to use, creates the project in
my-worker, installs its dependencies, and generates types for its bindings.
If you leave out the directory, cf init asks for one.
Apart from node_modules and the lockfile from the install, cf init creates
these files:
- my-worker/
- .cloudflare/
- types/
- index.d.ts
- types/
- src/
- index.ts
- .gitignore
- cloudflare.config.ts
- package.json
- tsconfig.json
- vite.config.ts
- .cloudflare/
src/index.tsis the Worker.cloudflare.config.tsdescribes the Worker in TypeScript.vite.config.tsadds the Cloudflare Vite plugin, which runs your code in the Workers runtime during development and builds it for deployment.package.jsonhasdev,build, anddeployscripts that run the matchingcfcommands. It listscfand the Vite plugin 2.0 beta (@cloudflare/vite-plugin@beta), whichcfuses, but not Wrangler..cloudflare/types/index.d.tsholds generated binding and runtime types. The Vite plugin updates it when you runcf devorcf build. The generated.gitignoreexcludes.cloudflare/.
The Worker reads a WORLD binding and returns a greeting:
import { env } from "cloudflare:workers";
export default {
fetch() {
return new Response(`Hello ${env.WORLD}!`);
},
};import { env } from "cloudflare:workers";
export default {
fetch() {
return new Response(`Hello ${env.WORLD}!`);
},
} satisfies ExportedHandler;cloudflare.config.ts names the Worker, points to its entrypoint, and declares
the WORLD text binding. The annotations explain each field and builder:
Select a highlighted line to show its type and description below it.
export default defineConfig({ (defineConfig 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.
worker: { (worker reference)
workerOptionalLink to worker
worker?: ConfigInput<WorkerConfig>The Worker defined by this configuration.
name: "my-worker", (name reference)
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
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.
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.
WORLD: bindings.text("World"), (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
cf init sets compatibilityDate to a fixed, recent date that ships with
your version of cf. The cf-worker import attribute points the configuration
at your Worker module. cf reads the module path from it and does not load or
run your Worker code.
Start the development server:
cd my-worker
cf devOpen the local URL that cf dev prints, by default http://localhost:5173/.
The Worker responds with Hello World!.
Change the response in src/index.ts, save the file, and refresh the page. The
development server picks up the change without a restart.
In this project, cf dev does not accept options such as --port. To change
the port, set server.port in vite.config.ts.
-
If you have not signed in yet, sign in:
cf auth login -
Deploy the Worker:
cf deploycf deploybuilds the project, uploads the Worker, deploys it to your account, and prints the result. If you can access more than one account,cfasks which one to use. To learn how to set a default, refer to Select an account.
To check the build without deploying, run cf deploy --dry-run. A dry run
makes no API requests, so it works before you sign in.
In a script or CI job, cf init cannot ask questions, so pass the directory.
Choose the package manager with --package-manager, which accepts npm,
pnpm, yarn, or bun. Without it, cf init uses npm, unless you ran cf
through another package manager:
cf init my-worker --package-manager npmTo skip the installation, add --no-install. Then run your package manager's
install command in the project before you run cf dev.
cf can also set up an existing app. In the project directory, install its
dependencies, then run cf init .:
cf init .cf detects the framework and shows the settings it found, including the
Worker name, framework, build command, and output directory. After you confirm,
cf changes the project. For a Vite app, it:
- Installs
cfand@cloudflare/vite-pluginas development dependencies. - Adds the Cloudflare plugin to
vite.config.ts, or creates the file. - Creates
cloudflare.config.ts, with observability turned on. - Adds a
deployscript that runscf deploy. - Adds
.wrangler,.dev.vars*, and.env*entries to.gitignore. In a Git repository without a.gitignorefile, it creates one.
cf does not add .cloudflare/, where it writes builds and generated types, to
.gitignore. Add it yourself:
echo ".cloudflare/" >> .gitignorecf build and cf deploy run the framework's build command, such as
vite build, not the build script in package.json. To keep extra build
steps, refer to
How cf runs your project.
If you skip cf init ., then cf dev, cf build, and cf deploy run the same
setup the first time you use them. In CI, they apply the changes without
asking, so run cf init . locally and commit the result first. For details,
refer to Automatic configuration.
Plain Vite apps work with this flow. cf also detects other frameworks, such
as Astro, React Router, and SvelteKit, but detection does not mean the project
builds. For example, Astro 6 and later does not build with cf during the
beta.
- Add storage, queues, or other resources with bindings.
- Route traffic to your Worker with triggers.
- Learn how
cfdevelops, builds, and deploys projects in Develop, build, and deploy. - Explore every configuration option in the configuration explorer.