Environment variables in Remix template with Edge Functions

I created a new remix project using the netlify template: npx create-remix@latest --template netlify/remix-template followed by the rest of the setup in the readme.

When I run netlify dev I have to access env vars using process.env but when I use netlify server or run in production then Netlify.env.get() (or even Deno.env.get()) works as expected.

In my mind the expected behavior is that using Netlify.env.get() should work when using netlify dev but the error I get is “ReferenceError: Netlify is not defined”.

My current solution is to conditionally retrieve my env vars:

let ENV: Record<string, string> = {}

if (tyepof Netlify === undefined) {
  ENV = {
    FOO: process.env.BAR
  }
} else {
  ENV = {
    FOO: Netlify.env.get('BAR')
  }
}

export { ENV }

Separate but related issue: When referencing Netlify.env.get() I’m getting a “Cannot find name ‘Netlify’” error. I see the global decleration in "node_modules/@netlify/edge-functions/node/dist/bootstrap/globals" but I think the tsconfig might be misconfigured? Also the include property in the tsconfig has “netlify-edge-plugin.ts” which doesn’t seem to exist anywhere.

Sorry for the delay. Does process.env not work in production?

Currently what you’ve described sounds like expected behaviour from our end. When you run netlify dev, Netlify simply invokes a proxy server which proxies the requests to your application server, in this case, Remix. Remix doesn’t know about the Netlify global, it works with process.env. When you run netlify serve, Remix is no longer involved and Netlify mimics the production environment which has the Netlify global.

From what I’ve seen with other frameworks, process.env gets transpiled into the required code or some polyfills are included which ensure you don’t have to write any Netlify-specific code. You should write the framework-specific code and rest should be automatically handled for you.

I was just about to make a thread about this. I’m not able to access process.env properly. For example, in my loader function:

console.log(
    'ENV',
    process,
    process.env,
    process.env.GA_TRACKING_ID
  )

gives me this response:

[Remix server handler] ENV {
  env: [Object: null prototype] {
    GA_TRACKING_ID: "G-BLAHBLAH",
    ...other variables
  }
} {} undefined

For some reason, I can access the process object as a whole and pass all its contents inside env, including the variables and their values, but it passes an empty object if I use process.env and undefined for the variable directly.

Does it work with import {env} from 'node:process' and then env['name']?

I get a build error:
app/root.tsx (14:9): "env" is not exported by "__vite-browser-external", imported by "app/root.tsx"

I figured it out. Vite uses a different syntax for the environment variables, import.meta.env instead of process.env. I tried that before and it didn’t work, but the issue is that it requires the VITE_ prefix to expose these variables to the client. I didn’t know that included the loader functions since there was no issues in Remix dev, but I ran into this double gotcha.

I also want to continue using process.env instead of the other syntax, so I added it back here, filtering for the VITE_ prefix:

import { vitePlugin as remix } from "@remix-run/dev";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig, loadEnv } from 'vite';
import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin";

export default ({ mode }: { mode: string }) => {
  const env = loadEnv(mode, process.cwd(), 'VITE_')

  return defineConfig({
      plugins: [
          remix(),
          netlifyPlugin(),
          tsconfigPaths(),
      ],
      define: {
        'process.env': env
      }
  });
}