---
# System prepended metadata

title: NextJs Runtime Environment Variables
tags: [NextJs]

---

## [Runtime Environment Variables](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#runtime-environment-variables)

有兩種使用env的方式，分別是`build time`和`runtime` 

`build time`是在`next build`時就決定好env(專案根目錄.env)，但這方法會造成同樣的source code多個image版本

`runtime` env則可以build好image，後續再deploy時在決定env，可以避免因為env不同而build image，減少系統資源的消耗，對維護來說是比較好的選擇


如果使用的是`build time` env，要讓env可以在瀏覽器被存取，env必須有prefix `NEXT_PUBLIC_`，否則只能在server端被存取，在`next build`時，這些env會被轉成Javascript，但是如果使用的router不同，會不同的結果

要存取`runtime` env，Page-Router必須使用`GetServerSideProps`，App-Router則可以使用`unstable_noStore();`，官方建議使用App-Router，以下為每個組合的不同結果

### Page-Router

- `build time` env
只能讀取到有Prefix `NEXT_PUBLIC_`的env，無Prefix `NEXT_PUBLIC_`會閃一下後跳Error

- `build time` env with `GetServerSideProps`
不論是否有Prefix `NEXT_PUBLIC_`都會在瀏覽器上顯示

- `build time` env conbine `runtime` env 
無法讀取到`runtime` env,`runtime` env 會閃一下後跳Error

- `build time` env conbine `runtime` env with `GetServerSideProps`
**有Prefix** `NEXT_PUBLIC_`會被`runtime` env取代

- `runtime` env
無法顯示任何env

- `runtime` env with `GetServerSideProps`
不論是否有Prefix `NEXT_PUBLIC_`都會在瀏覽器上顯示


### App-Router
- `build time` env
不論是否有Prefix `NEXT_PUBLIC_`都會在瀏覽器上顯示

- `build time` env with `unstable_noStore();`
不論是否有Prefix `NEXT_PUBLIC_`都會在瀏覽器上顯示

- `build time` env conbine `runtime` env 
無法讀取到`runtime` env 

- `build time` env conbine `runtime` env with `unstable_noStore();`
**無Prefix** `NEXT_PUBLIC_`會被`runtime` env取代

- `runtime` env
無法顯示任何env

- `runtime` env with `unstable_noStore();`
不論是否有Prefix `NEXT_PUBLIC_`都會在瀏覽器上顯示

### 測試指令
```
docker compose up --build
```

- next.config.mjs
```typescript=
/** @type {import('next').NextConfig} */
const nextConfig = { output: "standalone" };

export default nextConfig;
```

- Dockerfile
```dockerfile=
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
    if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
    elif [ -f package-lock.json ]; then npm ci; \
    elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
    else echo "Lockfile not found." && exit 1; \
    fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN \
    if [ -f yarn.lock ]; then yarn run build; \
    elif [ -f package-lock.json ]; then npm run build; \
    elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
    else echo "Lockfile not found." && exit 1; \
    fi

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
```
- docker-compose.yaml
```yaml=
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: nextjspage
    ports:
      - "3000:3000"
    env_file:
      - env/staging.env

```

- index.tsx(Page-Router)
```typescript=
import type { InferGetServerSidePropsType, GetServerSideProps } from "next";

type RuntimeEnv = {
  backendUrl: string;
  apiPath: string;
  apiVersion: string;
  n_backendUrl: string;
  n_apiPath: string;
  n_apiVersion: string;
};

export const getServerSideProps = (async () => {
  // Fetch data from external API
  const runtimeEnv: RuntimeEnv = {
    backendUrl: process.env.NEXT_PUBLIC_BACKEND_URL || "",
    apiPath: process.env.NEXT_PUBLIC_API_PATH || "",
    apiVersion: process.env.NEXT_PUBLIC_API_VERSION || "",
    n_backendUrl: process.env.BACKEND_URL || "",
    n_apiPath: process.env.API_PATH || "",
    n_apiVersion: process.env.API_VERSION || "",
  };
  // Pass data to the page via props
  return { props: { runtimeEnv } };
}) satisfies GetServerSideProps<{ runtimeEnv: RuntimeEnv }>;

export default function Page({ runtimeEnv }: InferGetServerSidePropsType<typeof getServerSideProps>) {
  console.log(`===========`);
  console.log(`NODE_ENV: ${process.env.NODE_ENV}`);
  console.log(`BACKEND_URL: ${process.env.BACKEND_URL}`);
  console.log(`API_PATH: ${process.env.API_PATH}`);
  console.log(`API_VERSION: ${process.env.API_VERSION}`);
  console.log(`NEXT_PUBLIC_BACKEND_URL: ${process.env.NEXT_PUBLIC_BACKEND_URL}`);
  console.log(`NEXT_PUBLIC_API_PATH: ${process.env.NEXT_PUBLIC_API_PATH}`);
  console.log(`NEXT_PUBLIC_API_VERSION: ${process.env.NEXT_PUBLIC_API_VERSION}`);
  console.log(`===========`);
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24 bg-green-200">
      <p>BACKEND_URL: {runtimeEnv.backendUrl}</p>
      <p>API_PATH: {runtimeEnv.apiPath}</p>
      <p>API_VERSION: {runtimeEnv.apiVersion}</p>
      <p>NEXT_PUBLIC_BACKEND_URL: {runtimeEnv.n_backendUrl}</p>
      <p>NEXT_PUBLIC_API_PATH: {runtimeEnv.n_apiPath}</p>
      <p>NEXT_PUBLIC_API_VERSION: {runtimeEnv.n_apiVersion}</p>
    </main>
  );
}
```

- page.tsx(App-router)
```typescript=
import { unstable_noStore } from "next/cache";

export default function Home() {
  unstable_noStore();
  console.log(`===========`);
  console.log(`NODE_ENV: ${process.env.NODE_ENV}`);
  console.log(`BACKEND_URL: ${process.env.BACKEND_URL}`);
  console.log(`API_PATH: ${process.env.API_PATH}`);
  console.log(`API_VERSION: ${process.env.API_VERSION}`);
  console.log(`NEXT_PUBLIC_BACKEND_URL: ${process.env.NEXT_PUBLIC_BACKEND_URL}`);
  console.log(`NEXT_PUBLIC_API_PATH: ${process.env.NEXT_PUBLIC_API_PATH}`);
  console.log(`NEXT_PUBLIC_API_VERSION: ${process.env.NEXT_PUBLIC_API_VERSION}`);
  console.log(`===========`);

  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24 bg-green-200">
      <p>BACKEND_URL: {process.env.BACKEND_URL}</p>
      <p>API_PATH: {process.env.API_PATH}</p>
      <p>API_VERSION: {process.env.API_VERSION}</p>
      <p>NEXT_PUBLIC_BACKEND_URL: {process.env.NEXT_PUBLIC_BACKEND_URL}</p>
      <p>NEXT_PUBLIC_API_PATH: {process.env.NEXT_PUBLIC_API_PATH}</p>
      <p>NEXT_PUBLIC_API_VERSION: {process.env.NEXT_PUBLIC_API_VERSION}</p>
    </main>
  );
}

```