React Router
Prerequisites
Start with a React Router Framework Mode app using Vite and Node.js. Keep server rendering enabled. This guide uses @react-router/serve for production.
For a browser-only app using BrowserRouter or createBrowserRouter, follow the Vite guide.
Install
In your React Router project, install Dotenvx and the production server.
$ npm install @dotenvx/dotenvx @react-router/serve
$ pnpm add @dotenvx/dotenvx @react-router/serve
Encrypt
Start with a secret value in the .env file at your project root, like:
# .env
HELLO="Secret"
Encrypt it with a single command.
$ npx dotenvx encrypt
◈ encrypted .env (022 0D8) via .env.keys ⛉
$ pnpm exec dotenvx encrypt
◈ encrypted .env (022 0D8) via .env.keys ⛉
The values become ciphertext and only your private key can unlock them.
# .env
DOTENV_PUBLIC_KEY="0220d830351410598be484f43a7b07097e09851f50426832876e8b5815a1752990"
HELLO="encrypted:BHLTACNJMr00nTG6yXpkCyWFKF/MY0ajN855tg3uVtKopTe2AGzSkQlcPd21pTOT3Ci8IKrdIg2TMZFoq1mDR6yb06QCRvqHXtpkZkAHYCEHfeWqqC8tMFovcYq5JS2uZSrC/qUGDA=="
Commit
Commit your encrypted .env files with your code. It's safe. Now you can securely share secrets through git.
$ git add .env
$ git commit -m "encrypt .env"
Ship
Read your value in a server loader:
// app/routes/home.tsx
import { useLoaderData } from 'react-router'
export function loader() {
return { hello: process.env.HELLO }
}
export default function Home() {
const { hello } = useLoaderData<typeof loader>()
return <h1>Hello {hello}</h1>
}
Keep your home route registered in app/routes.ts:
// app/routes.ts
import { index, type RouteConfig } from '@react-router/dev/routes'
export default [
index('routes/home.tsx'),
] satisfies RouteConfig
Keep any other routes in that array. HELLO is a demonstration value: loader results reach the browser. Use real secrets inside server loaders or actions without returning them, and keep secret access out of clientLoader.
Update these scripts in package.json, keeping your other scripts:
{
"scripts": {
"dev": "dotenvx run --strict -- react-router dev",
"build": "react-router build",
"start": "dotenvx run -f .env.production --strict -- react-router-serve ./build/server/index.js"
}
}
Run your app:
$ npm run dev
⟐ injected env (2) from .env (022 0D8) via .env.keys
$ pnpm dev
⟐ injected env (2) from .env (022 0D8) via .env.keys
Dotenvx loads and decrypts .env before React Router starts. Your loader reads process.env on the server at request time.
Visit http://localhost:5173 to see Hello Secret.
Public browser variables Alternative →
Share
Have teammates? Share access with Dotenvx Armor ⛨
Log in to Dotenvx.
$ npx dotenvx login
◉ logged in (username)
$ pnpm exec dotenvx login
◉ logged in (username)
Create the Armored Key ⛨
$ npx dotenvx armor up
⛨ armored .env (022 0D8)
$ pnpm exec dotenvx armor up
⛨ armored .env (022 0D8)
Invite your teammate.
$ npx dotenvx armor invite
⛨ invited [email protected] to team
$ pnpm exec dotenvx armor invite
⛨ invited [email protected] to team
Your teammate accepts the invitation, pulls the repository, installs dependencies, and logs in with dotenvx login. They can then run the app:
$ npm run dev
⟐ injected env (2) from .env (022 0D8) via Armor ⛨
$ pnpm dev
⟐ injected env (2) from .env (022 0D8) via Armor ⛨
Visit http://localhost:5173 to see Hello Secret.
Share a private key Alternative →
Production
Create a .env.production file.
# .env.production
HELLO="Production"
Encrypt it with an Enclaved Key ◊
$ npx dotenvx encrypt -f .env.production
◈ encrypted .env.production (022 0D8) via Armor Enclave ◊
$ pnpm exec dotenvx encrypt -f .env.production
◈ encrypted .env.production (022 0D8) via Armor Enclave ◊
When prompted, choose Enclaved, select your deployment service, connection, and resource, and use DOTENV_PRIVATE_KEY_PRODUCTION as the private key name.
Commit .env.production.
$ git add -f .env.production
$ git commit -m "encrypt .env.production"
Install dependencies and build your app in your deployment build step:
$ npm install
$ npm run build
$ pnpm install
$ pnpm build
This server-rendered example only needs its secret at runtime, so the build script does not decrypt it.
Deploy the compiled build directory, package.json, runtime dependencies, and encrypted .env.production file to the selected resource. Keep .env.production at the project root and .env.keys on your local machine.
Set HOST to 0.0.0.0 and PORT to the port your host expects. From the project root, run:
$ npm start
$ pnpm start
Dotenvx loads and decrypts .env.production with your Enclaved Key ◊
Open your deployed app's URL to see Hello Production.
Build-time configuration Alternative →
Deploy with a private key Alternative →
For custom servers or edge hosts, use the matching React Router deployment setup; the start script above targets Node.js.
Conclusion
You've encrypted your secrets, shared access with Armor, and loaded production secrets in React Router with an Enclaved Key. Your secrets now travel with your code.