Managing Environment Variables and Secrets for Next.js in Kubernetes

Managing Environment Variables and Secrets for Next.js in Kubernetes



This is Part 5 of the series: Self-Hosting Next.js in Kubernetes (Without Vercel).

By now, your Next.js standalone app is:

  • Built correctly
  • Running in a minimal Docker image
  • Deployed on OpenShift or Kubernetes

The next challenge is managing configuration and secrets without rebuilding your image every time.


Build-Time vs Runtime Environment Variables

This distinction is critical in Next.js.

Build-Time Variables

  • Resolved during npm run build
  • Inlined into the JavaScript bundle
  • Cannot be changed without rebuilding

Examples:

NEXT_PUBLIC_API_URL
NEXT_PUBLIC_FEATURE_FLAG

Runtime Variables

  • Read when server.js starts
  • Can be changed via Kubernetes
  • Ideal for secrets and environment-specific config
DATABASE_URL
REDIS_HOST
INTERNAL_API_TOKEN

What Works Best for Standalone Deployments

For self-hosted Next.js:

  • Use build-time vars sparingly
  • Prefer runtime vars for everything else
  • Avoid baking secrets into the image

The standalone server behaves like a normal Node.js app — use that to your advantage.


Using ConfigMaps

ConfigMaps are ideal for non-sensitive configuration.

apiVersion: v1
kind: ConfigMap
metadata:
  name: example-nextjs-config
data:
  LOG_LEVEL: "info"
  API_TIMEOUT_MS: "5000"

Attach them to your Deployment:

envFrom:
  - configMapRef:
      name: example-nextjs-config

Using Secrets

Secrets should be used for anything sensitive.

apiVersion: v1
kind: Secret
metadata:
  name: example-nextjs-secrets
type: Opaque
stringData:
  DATABASE_URL: "postgres://..."
  API_TOKEN: "********"

Mount them into the container:

envFrom:
  - secretRef:
      name: example-nextjs-secrets

Your standalone server can access them via process.env.


Common Mistake: NEXT_PUBLIC at Runtime

Variables prefixed with NEXT_PUBLIC_ are:

  • Resolved at build time
  • Embedded into client-side JavaScript

Changing them in Kubernetes will not update the UI.

If a value must be dynamic, fetch it from the server at runtime instead of embedding it in the bundle.


Example Deployment Snippet

containers:
  - name: web
    image: example-nextjs:latest
    envFrom:
      - configMapRef:
          name: example-nextjs-config
      - secretRef:
          name: example-nextjs-secrets

No rebuild required — just redeploy.


Security Best Practices

  • Never commit secrets to source control
  • Rotate secrets without rebuilding images
  • Limit access via RBAC
  • Use external secret managers when available

Series Progress

Self-Hosting Next.js in Kubernetes (Without Vercel)


Final Thoughts

Once you separate build-time and runtime configuration, Next.js becomes much easier to operate in Kubernetes.

In the final post, we’ll cover health probes, graceful shutdowns, and horizontal scaling strategies.

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular posts from this blog

fixed: embedded-redis: Unable to run on macOS Sonoma

Copying MDC Context Map in Web Clients: A Comprehensive Guide

Reset user password for your own Ghost blog