Monorepo on Cloudflare Workers: Unable to pass down Environment Variables

Hey guys, new to Cloudflare Workers, Wrangler, and D1. Trying to scaffold out to use Cloudflare Workers in a monorepo structure, and get it deployed: Monorepo Structure:
- apps/
- - web/
- - server/
- packages
- - db/
- - auth/
- - .../
- apps/
- - web/
- - server/
- packages
- - db/
- - auth/
- - .../
I'm using Vite (React), Drizzle, Better-Auth, and Hono. apps/server/wrangler.toml:
name = "..."
main = "src/index.ts"
compatibility_date = "2025-04-03"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DATABASE_URL"
database_id = "4a72636b-dcca-4307-9530-eadca0029da4"
migrations_dir = "../../packages/db/src/migrations"
database_name = "db-name"

[vars]
CORS_ORIGIN = "..."

[vars.prod]
CORS_ORIGIN = "..."
name = "..."
main = "src/index.ts"
compatibility_date = "2025-04-03"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DATABASE_URL"
database_id = "4a72636b-dcca-4307-9530-eadca0029da4"
migrations_dir = "../../packages/db/src/migrations"
database_name = "db-name"

[vars]
CORS_ORIGIN = "..."

[vars.prod]
CORS_ORIGIN = "..."
apps/web/wrangler.toml:
name = "..."
compatibility_date = "2025-04-03"

[assets]
not_found_handling = "single-page-application"

[vars]
VITE_SERVER_URL = "http://localhost:3000"

[vars.prod]
VITE_SERVER_URL = "..."
name = "..."
compatibility_date = "2025-04-03"

[assets]
not_found_handling = "single-page-application"

[vars]
VITE_SERVER_URL = "http://localhost:3000"

[vars.prod]
VITE_SERVER_URL = "..."
I had a few questions: - How does my web/ monorepo get access to the workers environment variables? When I check the settings under Environment Variables, it says that static assets do not have access to environment variables. - How does my db/ package (which is Drizzle), gain access to the D1 instance? This is mainly for running the cli, i.e. migration, pushing.
4 Replies
olafg
olafg5w ago
The variables are defined in each wrangler.toml (i.e. web and server). The worker that runs in web has access to the variables defined in web/wrangler.toml and likewise for the server worker For local development you define the variables in .dev.vars in each app. In order for the variables to be available in the runtime context you have to run wrangler types first
Gab
Gab5w ago
Cloudflare Docs
Secrets
Store sensitive information, like API keys and auth tokens, in your Worker.
Gab
Gab5w ago
for drizzle configuration (for migrations), its a little bit more harder you can see these docs: https://orm.drizzle.team/docs/connect-cloudflare-d1 https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit at my personal projects, i use this configuration (to allow me to apply migration at local/production enviroments) here a axample configration drizzle.config.ts
import fs from "node:fs";
import path from "node:path";
import { defineConfig } from "drizzle-kit";

// to get local miniflare-sqlite file
function getLocalD1DB() {
try {
const basePath = path.resolve(".wrangler");
const dbFile = fs
.readdirSync(basePath, { encoding: "utf-8", recursive: true })
.find((f) => f.endsWith(".sqlite"));

if (!dbFile) {
throw new Error(`.sqlite file not found in ${basePath}`);
}

const url = path.resolve(basePath, dbFile);
console.log(url);

return url;
} catch (err) {
console.log(`Error ${err}`);
}
}

// if env is prodction. it will use your d1 configuraton envs to apply the migrations at prod, if not, it will aplly to your locally sqlite file
export default defineConfig({
dialect: "sqlite",
schema: "./src/models/models.ts",
out: "./migrations",
...(process.env.NODE_ENV === "production"
? {
driver: "d1-http",
dbCredentials: {
accountId: process.env.CLOUDFLARE_D1_ACCOUNT_ID,
databaseId: process.env.CLOUDFLARE_DATABASE_ID,
token: process.env.CLOUDFLARE_D1_API_TOKEN,
},
}
: {
dbCredentials: {
url: getLocalD1DB(),
},
}),
});
import fs from "node:fs";
import path from "node:path";
import { defineConfig } from "drizzle-kit";

// to get local miniflare-sqlite file
function getLocalD1DB() {
try {
const basePath = path.resolve(".wrangler");
const dbFile = fs
.readdirSync(basePath, { encoding: "utf-8", recursive: true })
.find((f) => f.endsWith(".sqlite"));

if (!dbFile) {
throw new Error(`.sqlite file not found in ${basePath}`);
}

const url = path.resolve(basePath, dbFile);
console.log(url);

return url;
} catch (err) {
console.log(`Error ${err}`);
}
}

// if env is prodction. it will use your d1 configuraton envs to apply the migrations at prod, if not, it will aplly to your locally sqlite file
export default defineConfig({
dialect: "sqlite",
schema: "./src/models/models.ts",
out: "./migrations",
...(process.env.NODE_ENV === "production"
? {
driver: "d1-http",
dbCredentials: {
accountId: process.env.CLOUDFLARE_D1_ACCOUNT_ID,
databaseId: process.env.CLOUDFLARE_DATABASE_ID,
token: process.env.CLOUDFLARE_D1_API_TOKEN,
},
}
: {
dbCredentials: {
url: getLocalD1DB(),
},
}),
});
Drizzle ORM - Cloudflare D1
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.
Drizzle ORM - Cloudflare D1 HTTP API with Drizzle Kit
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.
Gab
Gab5w ago
at your wrangler.jsonc (se the drizle/d1 connections envs)
"vars": {
"CLOUDFLARE_D1_ACCOUNT_ID": "69b901..................", // the path paramter id deplayed at cloudfalre link when your enter at your account
"CLOUDFLARE_DATABASE_ID": "7606654b..............", // your d1 id
"CLOUDFLARE_D1_API_TOKEN": "kDb_...................", // refer to drizle previus docs link
"NODE_ENV": "production",
},
"d1_databases": [
{
"binding": "D1",
"database_id": "cf2eead-...............",
"database_name": "d1_database",
// "preview_database_id": "387a507d-........", // for --remote preview
"migrations_dir": "migrations" // put the path of your migrations folder at your monorepo projetct
}
],
"vars": {
"CLOUDFLARE_D1_ACCOUNT_ID": "69b901..................", // the path paramter id deplayed at cloudfalre link when your enter at your account
"CLOUDFLARE_DATABASE_ID": "7606654b..............", // your d1 id
"CLOUDFLARE_D1_API_TOKEN": "kDb_...................", // refer to drizle previus docs link
"NODE_ENV": "production",
},
"d1_databases": [
{
"binding": "D1",
"database_id": "cf2eead-...............",
"database_name": "d1_database",
// "preview_database_id": "387a507d-........", // for --remote preview
"migrations_dir": "migrations" // put the path of your migrations folder at your monorepo projetct
}
],
also, you can macro the drizle commands at your package.json
"scripts": {
"dev": "wrangler types && wrangler dev",
"deploy": "wrangler types && wrangler deploy --minify",
"cf-typegen": "wrangler types --env-interface CloudflareBindings",
"lint": "biome check",
"lint:fix": "pnpm lint --write",
"typecheck": "tsc --noEmit --pretty",
"dev:strict": "pnpm typecheck && wrangler dev",

"auth:generate": "npx --yes @better-auth/cli@latest generate --config src/core/auth.ts --output src/models/authModels.ts -y",
"db:generate": "drizzle-kit generate",
"db:migrate:dev": "wrangler d1 migrations apply d1_database --local",
"db:migrate:prod": "wrangler d1 migrations apply d1_database --remote",
"studio": "drizzle-kit studio",
"studio:prod": "NODE_ENV=production drizzle-kit studio",
"drizzle:up": "drizzle-kit up",
"amend": "drizzle-kit drop && drizzle-kit generate"
},
"scripts": {
"dev": "wrangler types && wrangler dev",
"deploy": "wrangler types && wrangler deploy --minify",
"cf-typegen": "wrangler types --env-interface CloudflareBindings",
"lint": "biome check",
"lint:fix": "pnpm lint --write",
"typecheck": "tsc --noEmit --pretty",
"dev:strict": "pnpm typecheck && wrangler dev",

"auth:generate": "npx --yes @better-auth/cli@latest generate --config src/core/auth.ts --output src/models/authModels.ts -y",
"db:generate": "drizzle-kit generate",
"db:migrate:dev": "wrangler d1 migrations apply d1_database --local",
"db:migrate:prod": "wrangler d1 migrations apply d1_database --remote",
"studio": "drizzle-kit studio",
"studio:prod": "NODE_ENV=production drizzle-kit studio",
"drizzle:up": "drizzle-kit up",
"amend": "drizzle-kit drop && drizzle-kit generate"
},

Did you find this page helpful?