Modul 9: Nuxt Fortgeschritten

Runtime Config & Umgebungsvariablen

Verwalte Konfigurationswerte und Secrets sicher mit runtimeConfig, .env-Dateien und dem useRuntimeConfig-Composable.

Konfiguration in Nuxt

Jede Anwendung braucht Konfigurationswerte: API-URLs, Secrets, Feature-Flags. Nuxt bietet ein durchdachtes System, das zwischen öffentlichen und privaten Werten unterscheidet und sich nahtlos mit Umgebungsvariablen verbindet.

Das Konzept basiert auf zwei Bereichen:

  • runtimeConfig – Private Werte, nur auf dem Server verfügbar
  • runtimeConfig.public – Öffentliche Werte, auch im Client verfügbar
🛤️

Rails-Vergleich

In Rails nutzt du Rails.application.credentials für Secrets und ENV['VARIABLE'] für Umgebungsvariablen. Nuxt kombiniert beides in runtimeConfig: Private Werte sind wie Credentials (nur serverseitig), öffentliche wie config/application.yml.

runtimeConfig definieren

Die Konfiguration wird in nuxt.config.ts definiert. Werte direkt unter runtimeConfig sind privat (nur Server), Werte unter public sind auch im Browser verfügbar:

nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // ⛔ Privat – nur auf dem Server verfügbar
    stripeSecret: 'sk_test_...',
    databaseUrl: 'postgresql://localhost/mydb',
    jwtSecret: 'mein-geheimes-token',

    // ✅ Öffentlich – auch im Browser verfügbar
    public: {
      apiUrl: 'https://api.example.com',
      appName: 'Mein Shop',
      sentryDsn: 'https://sentry.io/...'
    }
  }
})
🚫

Sicherheitsregel

Lege API-Keys, Datenbank-Passwörter und andere Secrets niemals unter runtimeConfig.public ab! Alles unter public wird in den Client-Bundle eingebettet und ist für jeden im Browser sichtbar.

useRuntimeConfig() verwenden

Mit dem useRuntimeConfig()-Composable greifst du auf die Konfiguration zu. Im Client sind nur die public-Werte verfügbar:

pages/dashboard.vue
<script setup lang="ts">
const config = useRuntimeConfig()

// ✅ Funktioniert – öffentlicher Wert
console.log(config.public.apiUrl)
// → "https://api.example.com"

// ⛔ undefined – privater Wert nicht im Client
console.log(config.stripeSecret)
// → undefined
</script>

<template>
  <div>
    <p>API: {{ config.public.apiUrl }}</p>
    <p>App: {{ config.public.appName }}</p>
  </div>
</template>

In Server-Routen hast du Zugriff auf alle Werte – auch die privaten:

server/api/payment.post.ts
// server/api/payment.post.ts
export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()

  // ✅ Auf dem Server: Zugriff auf ALLE Werte
  const stripe = new Stripe(config.stripeSecret)

  // ✅ Auch öffentliche Werte verfügbar
  console.log(config.public.apiUrl)

  const body = await readBody(event)

  const session = await stripe.checkout.sessions.create({
    line_items: body.items,
    mode: 'payment',
    success_url: `${config.public.apiUrl}/erfolg`,
    cancel_url: `${config.public.apiUrl}/warenkorb`,
  })

  return { url: session.url }
})
⚠️

Wenn du in einer Vue-Komponente auf config.stripeSecret zugreifst, ist der Wert undefined – private Werte werden nie an den Client gesendet. Das ist ein Sicherheitsfeature, kein Bug.

.env-Dateien

Nuxt liest automatisch .env-Dateien im Projekt-Root. Umgebungsvariablen überschreiben die Standardwerte aus nuxt.config.ts nach einem bestimmten Namensschema:

.env
# .env

# Private Werte (NUXT_ Präfix)
NUXT_STRIPE_SECRET=sk_live_echterkey123
NUXT_DATABASE_URL=postgresql://user:pass@db.example.com/prod
NUXT_JWT_SECRET=super-sicheres-geheimnis

# Öffentliche Werte (NUXT_PUBLIC_ Präfix)
NUXT_PUBLIC_API_URL=https://api.meinshop.de
NUXT_PUBLIC_APP_NAME=Mein Shop
NUXT_PUBLIC_SENTRY_DSN=https://abc@sentry.io/123
ℹ️

Namenskonvention

Nuxt mappt Umgebungsvariablen automatisch auf runtimeConfig: NUXT_-Präfix für private Werte, NUXT_PUBLIC_ für öffentliche. Verschachtelte Keys werden mit Unterstrichen getrennt: NUXT_PUBLIC_API_URLruntimeConfig.public.apiUrl.

.env.example
# .env.example – Vorlage für Teammitglieder

# Stripe
NUXT_STRIPE_SECRET=sk_test_...

# Datenbank
NUXT_DATABASE_URL=postgresql://localhost/myapp_dev

# JWT
NUXT_JWT_SECRET=ein-lokaler-schlüssel

# Öffentlich
NUXT_PUBLIC_API_URL=http://localhost:3000
NUXT_PUBLIC_APP_NAME=Mein Shop (Dev)
💡

.env.example

Erstelle immer eine .env.example mit allen benötigten Variablen (ohne echte Werte). Das hilft neuen Teammitgliedern beim Setup – wie config/database.yml.example in Rails.

Umgebungsspezifische Konfiguration

Für verschiedene Umgebungen (Development, Staging, Production) kannst du unterschiedliche Werte setzen:

nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      apiUrl: 'http://localhost:3000' // Fallback
    }
  },

  // Umgebungsspezifische Overrides
  $development: {
    runtimeConfig: {
      public: {
        apiUrl: 'http://localhost:3000'
      }
    }
  },

  $production: {
    runtimeConfig: {
      public: {
        apiUrl: 'https://api.meinshop.de'
      }
    }
  }
})

Alternativ nutzt du verschiedene .env-Dateien pro Umgebung:

Terminal
# Verschiedene .env-Dateien
.env                  # Standard (immer geladen)
.env.local            # Lokale Overrides (in .gitignore)
.env.production       # Nur in Production

# Nuxt lädt automatisch:
# 1. .env
# 2. .env.local (falls vorhanden)
# 3. Echte Umgebungsvariablen überschreiben .env-Werte

# Deployment-Beispiel:
NODE_ENV=production nuxt build
🛤️

Rails-Vergleich

Rails hat eingebaute Umgebungen (development, test, production) mit jeweils eigenen Config-Dateien. In Nuxt erreichst du das gleiche über .env-Dateien oder $development/$production-Overrides in nuxt.config.ts.

Praxisbeispiel: Komplette Konfiguration

Hier ein vollständiges Beispiel, das zeigt, wie alle Teile zusammenspielen:

nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // Server-only Secrets
    stripeSecret: '',       // von NUXT_STRIPE_SECRET
    smtpPassword: '',       // von NUXT_SMTP_PASSWORD
    databaseUrl: '',        // von NUXT_DATABASE_URL

    // Öffentliche Werte
    public: {
      apiUrl: '',           // von NUXT_PUBLIC_API_URL
      appName: 'Mein Shop',
      appVersion: '1.0.0',
      features: {
        darkMode: true,
        newsletter: true
      }
    }
  }
})
composables/useAppConfig.ts
// composables/useAppConfig.ts
export function useAppConfig() {
  const config = useRuntimeConfig()

  const apiUrl = computed(() => config.public.apiUrl)
  const appName = computed(() => config.public.appName)
  const isDarkModeEnabled = computed(
    () => config.public.features.darkMode
  )

  // API-Helper mit voreingestellter Base-URL
  async function apiFetch<T>(path: string, options?: any) {
    return $fetch<T>(`${apiUrl.value}${path}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...options?.headers
      }
    })
  }

  return {
    apiUrl,
    appName,
    isDarkModeEnabled,
    apiFetch
  }
}

Zusammenfassung

KonzeptNuxtRails
SecretsruntimeConfig.secretKeyRails.application.credentials.secret_key
Öffentliche ConfigruntimeConfig.public.apiUrlRails.configuration.api_url
Env-Variablen.env + NUXT_-Präfix.env + dotenv Gem
ZugriffuseRuntimeConfig()ENV['KEY']