Skip to content

Commit a08b600

Browse files
docs: Runtime env docs (#4797)
With discussions with @schiller-manuel and the amount of time this issue has been brought up on Discord, I feel adding precisions and more explicit examples on how to deal with runtime env variables on the client could help. --------- Co-authored-by: Tanner Linsley <[email protected]>
1 parent 9374fac commit a08b600

File tree

2 files changed

+114
-11
lines changed

2 files changed

+114
-11
lines changed

docs/router/framework/react/how-to/use-environment-variables.md

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -514,22 +514,75 @@ module.exports = {
514514

515515
**Solutions**:
516516

517-
1. **Add correct prefix**: Use `VITE_MY_VARIABLE` for Vite, `PUBLIC_MY_VARIABLE` for Rspack
518-
2. **Restart dev server**: Environment changes require restart
519-
3. **Check file location**: `.env` must be in project root
520-
4. **Verify bundler configuration**: Ensure variables are properly injected
517+
1. **Add correct prefix**: Use `VITE_` for Vite, `PUBLIC_` for Rspack.
518+
Vite's default prefix may be changed in the config:
519+
```ts
520+
// vite.config.ts
521+
export const config = {
522+
// ...rest of your config
523+
envPrefix: 'MYPREFIX_' // this means `MYPREFIX_MY_VARIABLE` is the new correct way
524+
}
525+
```
526+
3. **Restart development server** after adding new variables
527+
4. **Check file location**: `.env` file must be in project root
528+
5. **Verify bundler configuration**: Ensure variables are properly injected
529+
6. **Verify variable**:
530+
- **In dev**: is in correct `.env` file or environment
531+
- **For prod**: is in correct `.env` file or current environment ***at bundle time***. That's right, `VITE_`/`PUBLIC_`-prefixed variables are replaced in a macro-like fashion at bundle time, and will *never* be read at runtime on your server. This is a common mistake, so make sure this is not your case.
521532

522533
**Example**:
523534

524535
```bash
525536
# ❌ Won't work (no prefix)
526-
API_URL=https://api.example.com
537+
API_KEY=abc123
527538

528539
# ✅ Works with Vite
529-
VITE_API_URL=https://api.example.com
540+
VITE_API_KEY=abc123
530541

531542
# ✅ Works with Rspack
532-
PUBLIC_API_URL=https://api.example.com
543+
PUBLIC_API_KEY=abc123
544+
545+
# ❌ Won't bundle the variable (assuming it is not set in the environment of the build)
546+
npm run build
547+
548+
# ✅ Works with Vite and will bundle the variable for production
549+
VITE_API_KEY=abc123 npm run build
550+
551+
# ✅ Works with Rspack and will bundle the variable for production
552+
PUBLIC_API_KEY=abc123 npm run build
553+
```
554+
555+
### Runtime Client Environment Variables at Runtime in Production
556+
557+
**Problem**: If `VITE_`/`PUBLIC_` variables are replaced at bundle time only, how to make runtime variables available on the client ?
558+
559+
**Solutions**:
560+
561+
Pass variables from the server down to the client:
562+
1. Add your variable to the correct `env.` file
563+
2. Create an endpoint on your server to read the value from the client
564+
565+
**Example**:
566+
567+
You may use your prefered backend framework/libray, but here it is using Tanstack Start server functions:
568+
569+
```tsx
570+
const getRuntimeVar = createServerFn({ method: 'GET' }).handler(() => {
571+
return process.env.MY_RUNTIME_VAR // notice `process.env` on the server, and no `VITE_`/`PUBLIC_` prefix
572+
})
573+
574+
export const Route = createFileRoute('/')({
575+
loader: async () => {
576+
const foo = await getRuntimeVar()
577+
return { foo }
578+
},
579+
component: RouteComponent,
580+
})
581+
582+
function RouteComponent() {
583+
const { foo } = Route.useLoaderData()
584+
// ... use your variable however you want
585+
}
533586
```
534587

535588
### Variable Not Updating

docs/start/framework/react/how-to/use-environment-variables.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,21 @@ for (const key of requiredClientEnv) {
372372

373373
**Solutions**:
374374

375-
1. Add `VITE_` prefix: `VITE_MY_VARIABLE`
376-
2. Restart development server after adding new variables
377-
3. Check file location (must be in project root)
378-
4. Verify variable is in correct `.env` file
375+
1. **Add correct prefix**: Use `VITE_` prefix (e.g. `VITE_MY_VARIABLE`)
376+
Vite's default prefix may be changed in the config:
377+
```ts
378+
// vite.config.ts
379+
export const config = {
380+
// ...rest of your config
381+
envPrefix: 'MYPREFIX_' // this means `MYPREFIX_MY_VARIABLE` is the new correct way
382+
}
383+
```
384+
2. **Restart development server** after adding new variables
385+
3. **Check file location**: `.env` file must be in project root
386+
4. **Verify bundler configuration**: Ensure variables are properly injected
387+
5. **Verify variable**:
388+
- **In dev**: is in correct `.env` file or environment
389+
- **For prod**: is in correct `.env` file or current environment ***at bundle time***. That's right, `VITE_`-prefixed variables are replaced in a macro-like fashion at bundle time, and will *never* be read at runtime on your server. This is a common mistake, so make sure this is not your case.
379390

380391
**Example**:
381392

@@ -385,6 +396,45 @@ API_KEY=abc123
385396
386397
# ✅ Works in client code
387398
VITE_API_KEY=abc123
399+
400+
# ❌ Won't bundle the variable (assuming it is not set in the environment of the build)
401+
npm run build
402+
403+
# ✅ Works in client code and will bundle the variable for production
404+
VITE_API_KEY=abc123 npm run build
405+
```
406+
407+
### Runtime Client Environment Variables at Runtime in Production
408+
409+
**Problem**: If `VITE_` variables are replaced at bundle time only, how to make runtime variables available on the client ?
410+
411+
**Solutions**:
412+
413+
Pass variables from the server down to the client:
414+
1. Add your variable to the correct `env.` file
415+
2. Create an endpoint on your server to read the value from the client
416+
417+
**Example**:
418+
419+
Using Tanstack Start server functions:
420+
421+
```tsx
422+
const getRuntimeVar = createServerFn({ method: 'GET' }).handler(() => {
423+
return process.env.MY_RUNTIME_VAR // notice `process.env` on the server, and no `VITE_` prefix
424+
})
425+
426+
export const Route = createFileRoute('/')({
427+
loader: async () => {
428+
const foo = await getRuntimeVar()
429+
return { foo }
430+
},
431+
component: RouteComponent,
432+
})
433+
434+
function RouteComponent() {
435+
const { foo } = Route.useLoaderData()
436+
// ... use your variable however you want
437+
}
388438
```
389439

390440
### Variable Not Updating

0 commit comments

Comments
 (0)