Pixelated image of Max Karlsson

How to access environment variables in Remix run on Cloudflare Pages

January 20, 2022

Ice hockey stick and puck on a frozen lake. Photo by Beppe Karlsson


After a long break from coding to spend time with my daughter and move houses (I would not recommend moving with a baby 😅), I'm finally getting back to it. A lot happened on the world wide web while I was out, and perhaps the one that made the most noise was the open sourcing of Remix. So I thought I'd give it a shot, and I'm glad I did.

Bootstrapping a Remix project with create-remix@latest lists Cloudflare Pages as a possible deployment target.

Great! I thought and immediately selected that option, watching the disk spin out the files while I listened to some retro synthwave.

The problem

I'll fast forward past the next bit because this isn't a review, but I got to a stage where I needed to use an environment variable. An API key that I didn't want to commit to source code.

But how do you add an environment variable in Remix on Cloudflare Pages? Not even Google seemed to know. I found some vague information about environment variables in Cloudflare Pages, and it was easy enough to add them to the settings interface. But how could I access those? And what about local development?

The Remix docs linked to the Cloudflare Documentation for environment variables, but that didn't help. Then the Remix docs went on to talk about dotenv. Ok, I know dotenv. Let's bring that in for local development, and I'll worry about deployment later. Cloudflare says no!

Cloudflare Pages run all the Remix backend functions in Cloudflare Workers, and guess what Cloudflare Workers isn't: a Node.js environment. So dotenv's internal imports of Node modules crashed the build.

There has to be a way, I thought. Then I changed the music to death metal and banged my head against the desk for an hour or so.

All the documentation I read for Cloudflare Pages and Workers told me I should be able to access environment variables as a param on the destructured argument that comes into the worker functions. But when I tried that in Remix, I got a big fat nothing. Or rather, undefined. So I started to dig into the source code for the Remix Cloudflare Pages integration. At this point, my brain was mush, so I can't tell you exactly how I figured it out, but eventually, I did, and there it was.

The solution

There's a folder called functions in the scaffolded project. That folder contains a single catch-all route (I can't remember if that's what Remix calls them) called [[path]].js. That file contains the following lines:

const handleRequest = createPagesFunctionHandler({

The createPagesFunctionHandler accepts another property on that destructured argument: getLoadContext. That's how you pass the context from Cloudflare Workers to Remix functions.

const handleRequest = createPagesFunctionHandler({
  getLoadContext: (context) => context,

That's it, as simple as that. One missing property on an object and no documentation (that I found over several hours of googling) to tell you how to add it or that it was needed wasted half a day for me. I hope this post will help you avoid going down the same path. Instead, keep those hours. Do something more useful with them. Maybe solve the next problem and write it up so that you've already written an article when I get to it.

Maybe you could solve how to add environment variables locally with Cloudflare Pages because I wasn't able to get that working other than by passing the variables in as arguments to wrangler when I run the script.

wrangler pages dev ./public --watch ./build --binding ENV_VAR=\"my-environment-variable-value\"

I'd love to hear about it if you found this helpful or fixed the local environment variable problem. I'm @BeppeKarlsson on Twitter. Drop me a line.

Ice hockey stick and puck on a frozen lake. Photo by Beppe Karlsson


Related posts

Recent posts

More from the blog

© Copyright 2022 Max Karlsson