Dennis Laurel
Guide: React + Vite + Bun (Runtime Variables with Nginx)

Guide: React + Vite + Bun (Runtime Variables with Nginx)

Guide: React + Vite + Bun (Runtime Variables with Nginx)

This setup allows your React application’s environment variables to be defined at container startup time, removing the need to generate a different build for each environment (Development, Staging, Production).

You can find more information about the plugin here: vite-plugin-runtime-env

1. Requirements

Install the plugin as a development dependency:

bun add -D vite-plugin-runtime-env

2. Vite Configuration (vite.config.ts)

The plugin automatically detects variables with the VITE_ prefix and prepares the code for runtime substitution.

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import runtimeEnv from "vite-plugin-runtime-env";

export default defineConfig({
  plugins: [
    react(),
    runtimeEnv() // Processes variables so Nginx can inject them
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

3. Nginx Configuration (nginx.conf)

Optimized configuration for Single Page Applications (SPA).

server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # SPA fallback
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Gzip for better performance
    gzip on;
    gzip_types text/plain text/css application/json application/javascript image/svg+xml;
}

4. Containerfile (Containerfile)

Uses an immutable template system to allow infinite variable changes without rebuilding.

# ---------- Build ----------
FROM oven/bun:1.3.0-alpine AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build

# ---------- Runtime ----------
FROM nginx:1.27-alpine
WORKDIR /usr/share/nginx/html

# Cleanup and configuration
RUN rm -f /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy the build output
COPY --from=build /app/dist .

# Create immutable template for envsubst
RUN cp index.html index.html.template

EXPOSE 80

# Dynamic injection at container startup
CMD ["/bin/sh", "-c", "envsubst < index.html.template > index.html && nginx -g 'daemon off;'"]

5. Docker Compose Deployment

Define your variables here. Changes will take effect with a simple container restart.

services:
  web:
    build: .
    environment:
      - VITE_API_URL=https://api.company.com
      - VITE_ENVIRONMENT=production
    ports:
      - "80:80"

💡 How It Works

  1. Build Time: The plugin vite-plugin-runtime-env leaves placeholders in the compiled JavaScript/HTML using the ${VITE_VARIABLE} format.

  2. Runtime (Container Startup): When the container starts, the envsubst command takes the template (index.html.template), finds those placeholders, and replaces them with the actual environment variable values.

  3. Persistence: By using a template file (.template), you can restart the container with new values as many times as needed—the variable “slots” are always available for reinjection.


Note: Make sure environment variables in your code are still accessed via import.meta.env.VITE_... to maintain compatibility with the plugin.