Understanding Environment Variables in Nuxt 3

This blog post delves into the usage and understanding of environment variables in Nuxt 3. It covers the importance of .env files, explains how to create and use them, and highlights best practices.

Michael Thiessen
Nuxt 3

Mastering Nuxt 3 course is here!

Get notified when we release new tutorials, lessons, and other expert Nuxt content.

Click here to view the Nuxt 3 course

Environment variables are the key to a secure app.

Nuxt gives us a few different ways to use them, depending on how we need to structure our project.

We’ll look at using environment variables through .env files, runtimeConfig, and the differences between the two and how to use them the best. At the end we’ll also discuss some common environment variables, and how to best store them.

But first, we need to make sure we're on the same page when it comes to .env files.

Understanding .env Files

.env files serve as a secure repository for sensitive information such as API keys and database credentials, ensuring they remain confidential and out of the codebase.

Imagine a .env file situated at the root of your Nuxt project, containing all the necessary environment variables that should be excluded from the public code repository.

Why do we do need it?

Because it helps in safeguarding your application's sensitive data from public exposure.

Also, .env files facilitate the seamless transition of settings across different environments — development, staging, and production — without the need to alter the code.

Nuxt simplifies the process by integrating dotenv support, automatically incorporating .env variables during the application's startup or build process.

It loads them automatically as soon as you run nuxi build or nuxi dev.

And for different environments, you can specify an alternative .env file using the --dotenv flag with Nuxt CLI commands.

Crafting a .env File

To create a .env file, simply create a new file named .env at the root of your Nuxt project and populate it with your variables:

# .env
COFFEE_SHOP_API_URL=https://api.coffeemagic.com
COFFEE_SHOP_SECRET_KEY=SuperSecret123!

In this instance, COFFEE_SHOP_API_URL refers to the URL for your coffee shop's backend API, while COFFEE_SHOP_SECRET_KEY is the confidential key for API authentication.

We'd use them in any part of our app this way:

process.env.COFFEE_SHOP_API_URL

Best Practices for .env Files

But don't forget! It is imperative to exclude your .env file from version control to maintain the confidentiality of your secrets!

You can do this by adding it to your .gitignore file:

# .gitignore
.env

Now we'll look at how we can use runtimeConfig to manage our secrets more easily.

Configuration with runtimeConfig

runtimeConfig in Nuxt represents an advanced configuration layer, allowing you to define settings that are accessible on both the client and server sides — a few nice tricks to make development a bit easier.

It differs from appConfig in a few key ways, but we won't get into that here.

Understanding runtimeConfig

Within your nuxt.config file, runtimeConfig provides two distinct sections — one for private (server-side) and another for public (client-side) configuration.

This distinction is crucial for maintaining the confidentiality of server-side settings while providing necessary information to the client-side.

Consider the following example for a space-themed application:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    nasaApiKey: 'N@5@_Ap1_K3y', // Keep this secret
    public: {
      marsWeatherApiEndpoint: '/api/mars-weather' // Publicly accessible
    }
  }
})

Here, nasaApiKey is a private key, whereas marsWeatherApiEndpoint is a public API endpoint.

Setting Defaults and Overriding with process.env

runtimeConfig allows you to establish default values within your nuxt.config.ts file, which can be overridden by process.env variables at runtime, eliminating the need for redeployment.

For example, in a music streaming service:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiEndpoint: process.env.MUSIC_STREAM_API_URL || '<https://api.musicstream.com>'
  }
})

The MUSIC_STREAM_API_URL variable, if set, will take precedence over the default value.

The NUXT_ Prefix for Environment Variables

To override runtimeConfig values at runtime, prepend your environment variables with the NUXT_ prefix. This tells Nuxt which variables it should use, and which to ignore.

But make sure that the rest of the name matches!

Let's say we have a gaming platform. Here your .env might look like this:

# .env
NUXT_GAMING_API_ENDPOINT=https://api.gamerworld.com

This variable would then be used in your nuxt.config.ts to configure the runtime settings:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    gamingApiEndpoint: '<https://default.gamerworld.com>'
  }
})

Here, gamingApiEndpoint in your runtimeConfi will be overwritten using the NUXT_GAMING_API_ENDPOINT. It's prefixed with NUXT_ and the rest of the name matches — though one is in SNAKE_CASE and the other in camelCase.

Client-Side Configuration

To get the public runtime configuration into a Vue component, you can use the useRuntimeConfig composable.

For instance, in a travel blog application that integrates an Instagram API, you could access the user ID to grab your IG feed like this:

<script setup lang="ts">
const config = useRuntimeConfig();
const instagramUserId = config.public.instagramUserId;
</script>

<template>
  <InstagramFeed :api-endpoint="instagramUserId" />
</template>

The runtimeConfig would be set up like this:

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      instagramUserId: 'someUserId',
      // Other public values...
    }
    // Other private values...
  }
})

It's super important that you limit client-side runtime configuration to public values only. They shouldn't contain any sensitive information to prevent security breaches.

Server-Side Configuration: Exclusive Access

Server middleware and API routes in Nuxt can fully utilize runtime configuration for sensitive operations.

For example, in an online bookstore, you might authenticate requests using a private API key:

// server/middleware/authenticate.ts
export default defineEventHandler((event) => {
  const config = useRuntimeConfig();
  const apiSecret = config.bookstoreApiKey;

  // Authenticate the request with the apiSecret
  // ...
});

Read-Only Server-Side Configuration

An important thing to note is that your runtimeConfig on the server side is immutable — it's readonly so you can't modify it in any way.

This is to avoid context sharing and the dreaded cross-request state pollution (good thing that Nuxt worries about that for us).

What should be public vs. private?

Now that you know how to keep things private or let them be public, it's important to know what to put where.

Public runtime configuration is intended for information that can be disclosed, such as API endpoints for data retrieval or UI feature flags.

Private runtime configuration, on the other hand, is reserved for sensitive data like secret keys and database connection strings.

Here is a quick guideline for categorizing some more common things:

  • API base URL: Public
  • API secret key: Private
  • Database connection string: Private
  • Third-party service API keys: Private
  • Application feature flags: Public
  • Analytics tracking ID: Public
  • CDN base URL: Public
  • Email service credentials: Private
  • Payment gateway keys: Private

Maintaining a good distinction between public and private configurations is really important for the security of your app.

Conclusion

As a dev, you need to balance the need for security with flexibility and ease of development.

.env files and runtimeConfig form the foundation of your Nuxt project's environment variable management, allowing you to stay secure while making development a breeze.

Michael Thiessen
Michael is a passionate full time Vue.js and Nuxt.js educator. His weekly newsletter is sent to over 11,000 Vue developers, and he has written over a hundred articles for his blog and VueSchool.

Follow MasteringNuxt on