Background
I wanted to deploy a SPA (single page application) to Cloudflare and right now Cloudflare offers 2 ways to deploy them
Using env vars in Static Assets is fairly straightforward. You declare them in the vars
scope in wrangler.toml
(or jsonc
) and you get access to them in the context passed on by the request. But there is an issue. You cannot use environment variables in Pages and also there is no wrangler.toml
to declare your variables.
I could have gone via the Static Assets route, but it was overkill just to use some environment variables. I wanted to deploy my SPA AND to also use the environment variables.
Vite to the rescue
Project setup
Bootstrap a basic React app via the Cloudflare CLI. I’m using bun
bun create cloudflare@latest react-env --framework=react
- Choose Pages.
- Choose your preferred variant. I’m choosing TypeScript.
- Open the project.
Let’s say you want to have different API URL per environment. To do so, open vite.config.ts
(or vite.config.js
) file and update it like so
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
// https://vite.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [react()],
define: {
'import.meta.VITE_API_URL':
mode === 'development' ? undefined : 'process.env.VITE_API_URL',
},
}));
In the above config, VITE_API_URL
is the API URL our app would need. To make it work locally, create a .env
file and update it like so
VITE_API_URL=YOUR_ACTUAL_API_URL
Now when you run the project, and use the variable via import.meta.env.VITE_API_URL
, everything would work as expected since during development we’re not replacing anything.
Deployment
That’s all good, but what about when the app is deployed to Ccloudflare? As with everything, we again have 2 options
- Setting the variables in the dashboard
- Using GitHub Actions
Setting the variables in the dashboard
- Log into your Cloudflare dashboard.
- Create a Pages project.
- Via their GitHub connection, select your project.
- Create a plain text variable via project settings for Production and Preview environments.
- On the next deployment, everything should be working.
Using GitHub Actions
Create a Pages project in Cloudflare dashboard since we would be using the name in the Action. Here is a bare minimum Action which you can use via bun
name: Deploy Pages
on:
push:
branches:
- main
- dev
paths:
- '.github/workflows/workflow.yml'
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.17.0'
- name: Install Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Build
run: bun run build
env:
VITE_API_URL: ${{ github.ref == 'refs/heads/dev' && 'https://dev.example.com' || 'https://example.com' }}
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=your-cf-project-name
- We’re running the Action on
dev
andmain
branches. - In the Build step, we’re setting the variables we want to use for each branch.
- In the Deploy to Cloudflare step, we’re deploying the app to our account via
CLOUDFLARE_API_TOKEN
andCLOUDFLARE_ACCOUNT_ID
. To know how to get these, you can refer to this section of my blog post. - Replace
your-cf-project-name
with the project name you created earlier.
Conclusion
In both of these methods, we’re essentially replacing the variable names which we’re using with the actual variables’ content during the build step allowing us to use environment variables even in Cloudflare Pages.
Enjoy 🥳