Edit

Environment Variables

Define

Environment variables can be defined in .env, .env.development, and .env.production files:

# .env
 
# This environment variable is available only on the server-side
DATABASE_PASSWORD=e9wd!1hw1@#231
# This environment variable is available on both the server- and client-side
PUBLIC_ENV__CONTACT_EMAIL=hello@example.org

Only environment variables prefixed with PUBLIC_ENV__ are available on the client-side.

⚠️

PUBLIC_ENV__* environment variables must never contain secret information — all PUBLIC_ENV__* values are visible to everyone because they are included in your client bundles which are public.

# .env.development
 
# This environment variable is available only in development
DATABASE_URL=postgresql://localhost:5432
# .env.production
 
# This environment variable is available only in production
DATABASE_URL=postgresql://database.example.com:5432

You can define further .env.[mode] files.

⚠️

If your repository is public (e.g. on GitHub), then make sure your .env files never contain secret information and, instead, consider defining secrets using:

Access

Use import.meta.env to access environment variables.

// /pages/movies/+data.js
 
const sql = new SQL({
  // These environment variable are available here because +data runs on the server-side
  username: import.meta.env.DATABASE_URL,
  password: import.meta.env.DATABASE_PASSWORD
})
 
export async function data(pageContext) {
  const { movies } = await sql.run('SELECT * FROM movies;')
  return movies
}
// /pages/movies/+data.ts
 
import type { PageContextServer } from 'vike/types'
 
const sql = new SQL({
  // These environment variable are available here because +data runs on the server-side
  username: import.meta.env.DATABASE_URL,
  password: import.meta.env.DATABASE_PASSWORD
})
 
export async function data(pageContext: PageContextServer) {
  const { movies } = await sql.run('SELECT * FROM movies;')
  return movies
}

For server only code, you can access environment variables using process.env, but we generally recommend against this because it won't be statically replaced.

// components/ContactUs.jsx
 
// The UI component <ContactUs> is loaded on the client-side
 
// This environment variable is available on the client-side: it's prefixed with PUBLIC_ENV__
const email = import.meta.env.PUBLIC_ENV__CONTACT_EMAIL
 
function ContactUs() {
  return <p>Contact us at {email}</p>
}

Keep in mind that import.meta.env.SOME_ENV is statically replaced:

// ❌ Won't work
import.meta.env['SOME_ENV']
// ❌ Won't work
const { SOME_ENV } = import.meta.env
// ✅ Works
import.meta.env.SOME_ENV

TypeScript

For improved DX, consider using zod, for example:

See also: Vike's plan for built-in TypeScript support.

Static replacement

For better tree shaking (aka dead code elimination), import.meta.env.SOME_ENV is statically replaced with its value. For example:

// src/someFile.js [source code in Git repository]
 
console.log('value:', import.meta.env.DISABLE_TRACKING)
 
if (import.meta.env.DISABLE_TRACKING === 'true') {
  console.log('Tracking is disabled')
} else {
  await import('some-heavy-tracking-library')
}
# .env
 
DISABLE_TRACKING='true'

The file src/someFile.js is built to:

// dist/server/chunks/chunk-DdwTql6x.js [built code deployed to production]
 
console.log("value:", "true");
console.log("Tracking is disabled");

Note how the import() is completely removed, resulting in more lightweight production bundles.

Config files

In config files, import.meta.env isn't available (neither vite.config.js nor +config.js).

Use process.env instead of import.meta.env.

Public allowlist

The following environment variables can be accessed from the client-side without having to prefix them with PUBLIC_ENV__:

  • STORYBOOK
💚

See also