Cloudflare Workers for Noobs
Hello there, I am the noob writing down notes about my learnings while I play with Cloudflare Workers. My aim is to provide a TL;DR resource for people who are approaching them for the first time.
This article focuses on the Cloudflare Workers developer experience and talks about deploying, managing environment variables and doing other configuration/operation tasks.
Here I assume that you know what Wrangler is.
This is a work in progress so please suggest an edit if any of the information in this page is inaccurate or can be improved.
Environments
In workers you define environments upon deploy or when you run in development with the wrangler flag --env
:
wrangler dev --env dev
wrangler deploy --env production
This is for example because you can have a remote dev environment or [insert other clever reasons here].
Every environment then can have its own configuration in wrangler.toml
under [env.name]
:
#########################################################
## common
main = "src/worker.ts"
compatibility_date = "2023-05-18"
#########################################################
## development
[env.dev]
name = "giuseppe-worker-dev"
#########################################################
## production
[env.production]
name = "giuseppe-worker"
Each environment will inherit the common config.
Environment Variables
Environment variables in workers are not global. They are passed to your worker handler as the env
argument:
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
console.log(JSON.stringify(env, null, 2));
}
This means that you need to pass the env
object around whenever you need to access an environment variable.
If you are coming from Node.js this will be annoying - deal with it. There is however the possibility to define global constants (more on it later).
If you scaffold the worker with wrangler you can define the type definitions for Env
in worker-configuration.d.ts
.
Defining Variables
Generally Cloudflare suggests to use wrangler.toml
rather than the Cloudflare Dashboard (or CLI?) as the source of truth. I am not sure I like this a lot but shrug.
What I learnt the hard way is that you cannot have some environment vars defined in the dashboard and others in wrangler.toml
.
Well actually you can but probably it is a bad idea.
If you like bad ideas and want to spread your variables here and there you will need to add a configuration flag to your wrangler.toml
called keep_vars
to preserve your dashboard variables on publish:
keep_vars = true
Anyway I wouldn't use this.
What really matters is that you figure out what is an actual secret and what is an environment variable that can easily go public to GitHub for example.
Probably most of your variables are API keys, access tokens and are confidential therefore they should be secrets that should be stored encrypted via the dashboard or with the CLI.
Development Variables
In contrast to other Verce...rvices, you won't host your local env variables on Cloudflare and pull them locally when developing. That would be an incredible DX.
Instead you need to keep them local either in wrangler.toml
or, if you don't want to version control them, put them in a file called .dev.vars
.
In .dev.vars
(remember to add it to .gitignore
):
myVar = "myValue"
alternatively in wrangler.toml
(this will go to GitHub etc):
#########################################################
## development
[env.dev]
name = "giuseppe-worker-dev"
[env.dev.vars]
myVar = "myValue"
Now myVar
can be accessed via env
(remember to wrangle dev --env dev
):
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
console.log(env.myVar)
}
In local development you will end up defining secrets as regular environment variables therefore probably .dev.vars
is a better place to store variables.
Defining Global Constants
In addition to variables it is possible to define global constants that will be statically replaced at build time.
This can be useful to define the equivalent of Node.js process.env.NODE_EV
for example.
To do so you can declare a define
section in your wrangler.toml
:
#########################################################
## common
main = "src/worker.ts"
compatibility_date = "2023-05-18"
#########################################################
## development
[env.dev]
name = "giuseppe-worker-dev"
[env.dev.define]
ENVIRONMENT = "'development'"
#########################################################
## production
[env.production]
name = "giuseppe-worker"
[env.production.define]
ENVIRONMENT = "'production'"
and magically you can access it in your worker:
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
if (ENVIRONMENT === "development") {
console.log(crackAJoke());
}
}
Keep in mind that this is not a replacement for environment variables and shouldn't be used to store secrets.
Finally you may want to add ENVIRONMENT
to your Worker's type definitions in worker-configuration.d.ts
:
declare var ENVIRONMENT: "development" | "production";
interface Env {
myVar: string;
}
To be continued...