window is not defined when trying to access environment variables in Remix

Solution 1:

You can't access window object in that code (component render), because it runs both on the server (because of server side rendering) and on the client too (just as regular client side React app). And on the server there is no window object or any other browser APIs. So you need to write that code that way so it could run both on the server and the client.

You can still use window object later though, for example in useEffect or some onClick handler, because this code will only run on the client side:

// both this cases will work fine
  useEffect(() => {
    console.log(window.ENV);
  }, []);

// ...

      <button
        onClick={() => {
          console.log(window.ENV);
        }}
      >
        Log env
      </button>

But sometimes you need those env values right away, directly in the render method. What you can is to use loader function in combination with useLoaderData hook, like that:

export function loader() {
  // process.env is available here because loader runs only on the server side
  return {
    SOME_SECRET: process.env.SOME_SECRET
  };
}

export default function Index() {
  const data = useLoaderData();

  // here you can use everything that you returned from the loader function
  console.log(data.SOME_SECRET);

  return <div>{/* ... */}</div>
}