Environment Variables

Environment variables are a way to store configuration values or sensitive data that should not be included directly in your application code. These variables are typically used for things like API keys, database connection strings, or other environment-specific settings.

Types of Environment Variables

Build-time

  • Environment variables which are prepended with PUBLIC_ and are available both on the client and the server.

Server-side

  • Environment Variables that are only accessible on the server.

IMPORTANT! DO NOT use build-time environment variables, (ie. variables that start with PUBLIC_) to store any sensitive information, such as API keys, secrets, passwords, etc. These variables are accessible in the browser ONLY PUBLIC DATA.

.env.local
# This will only be available when run on the server
API_KEY=secretApiKeyHere
# This will be available everywhere
PUBLIC_API_URL=https://api.example.com

Default Environment Variables

QwikCity includes a few environment variables out of the box

  • BASE_URL: string - Returns the base url for the page,
  • MODE: string - Returns the rendering mode,
  • DEV: boolean - Returns if you are in development mode,
  • PROD: boolean - Returns if you are in production mode,
  • SSR: boolean - Returns whether if this was rendered with ssr or not

The preferred method for accessing environment variables in QwikCity is via import.meta.env.* (client side) or through the Request object when run server side.

process.env is a Node.js only API, and should be avoided at all costs.

Build-time variables

Build-time variables are powered by Vite. They are defined in .env files and are available in the browser and in the server-side code.

Notice that build-time variables should be considered as public, since they will be hardcoded in the browser build, which can be easily read by anyone.

Build-time variables are prefixed by default with PUBLIC_ and can be accessed with with import.meta.env.PUBLIC_*.

Defining Variables

.env.local
PUBLIC_API_URL=https://api.example.com

Usage

src/routes/index.tsx
import { component$ } from '@builder.io/qwik';
 
export default component$(() => {
  // `import.meta.env.PUBLIC_*` variables can be read anywhere, including browser
  return <div>PUBLIC_API_URL: {import.meta.env.PUBLIC_API_URL}</div>
})

import.meta.env.PUBLIC_* variables can be read anywhere, but do not put any sensitive information in them, since they will be visible to the client.

Server-side Variables

Server-side variables are fundamentally runtime variables that are only available in the server-side code.

They are not known at build-time and are not available in the browser, so they can be considered as private.

During production, setting server-side variables is very platform specific. Most of the platforms allow you to set environment variables from their dashboard, or CLI. Please, refer to your platform (cloudflare, vercel, netlify) documentation for more information.

Special Considerations for Docker and Fastify:

  • Docker: While Docker allows the inclusion of environment variables directly in the Dockerfile, this method can expose sensitive data. A more secure practice is to manage these variables at runtime using Docker Compose. For example:
docker-compose.yml
version: '3.8'
services:
 your-service:
   image: your-image-name
   environment:
     - FOO=BAR
  • Fastify within Docker: Environment variables placed in .env or .env.local files may not be automatically recognized in production environments when using Fastify. For these settings to take effect it may be necessary to explicitly load them within your Fastify application or pass them through Docker's environment management system (Docker Compose) as shown above

Defining Variables

.env.local
DB_PRIVATE_KEY=123456789

Make sure you never commit .env.local files to git.

Usage Examples

Server-side variables can only be accessed in server-only APIs that expose the RequestEvent object, such as routeLoader$(), routeAction$(), server$() and endpoint handlers such as onGet, onPost, onRequest etc.

src/routes/index.tsx
import {
  routeLoader$,
  routeAction$,
  server$,
  type RequestEvent,
} from '@builder.io/qwik-city';
 
export const onGet = (requestEvent: RequestEvent) => {
  console.log(requestEvent.env.get('DB_PRIVATE_KEY'));
};
 
export const onPost = (requestEvent: RequestEvent) => {
  console.log(requestEvent.env.get('DB_PRIVATE_KEY'));
};
 
export const useAction = routeAction$(async (_, requestEvent) => {
  console.log(requestEvent.env.get('DB_PRIVATE_KEY'));
});
 
export const useLoader = routeLoader$(async (requestEvent) => {
  console.log(requestEvent.env.get('DB_PRIVATE_KEY'));
});
 
export const serverFunction = server$(function () {
  // `this` is the `RequestEvent` object
  console.log(this.env.get('DB_PRIVATE_KEY'));
});

Usage in serverfull architecture (Example:Express)

For accessing the .env variables in serverfull architecture we need to use singleton design pattern, initialize the db in a plugin and access it with getDB wherever it is needed

src/util/db.ts
let _db!: AppDatabase;
 
export function getDB() {
  // eslint-disable-next-line
  if (!_db) {
    throw new Error('DB not set');
  }
  return _db;
}
 
export async function initializeDbIfNeeded(factory: () => Promise<AppDatabase>) {
  // eslint-disable-next-line
  if (!_db) {
    _db = await factory();
  }
}
export const onRequest: RequestHandler = async ({ env }) => {
  const url = env.get('PRIVATE_LIBSQL_DB_URL')!;
  const authToken = env.get('PRIVATE_LIBSQL_DB_API_TOKEN')!;
  await initializeDbIfNeeded(initLibSql(url, authToken));
};

Managing Environment Variables Throughout the Application Lifecycle

In modern applications, environment variables play a crucial role in managing application settings and configurations across various environments without hardcoding sensitive data into the source code.

Qwik City adaptors use the following:

  • Azure, Cloud Run, Netlify Edge, Node Server, use ORIGIN or URL
  • Cloudflare Pages uses CF_PAGES_URL or ORIGIN
  • Vercel uses VERCEL_URL

Note: This is not a comprehensive guide on environment variables, nor does it cover all of the 3rd-Party hosting scenarios. It is meant to give insight that can be applied across various environments.

See this video for a detailed explanation: https://youtu.be/NPf39RWc8LM

Contributors

Thanks to all the contributors who have helped make this documentation better!

  • manucorporat
  • the-r3aper7
  • mrhoodz
  • wtlin1228
  • RumNCodeDev
  • Jemsco