Skip to main content
Environment variables allow you to configure your Astro application without hardcoding values. Use them for API keys, database URLs, feature flags, and other configuration that changes between environments.

Using Environment Variables

Access environment variables through import.meta.env:
src/pages/index.astro
---
const apiKey = import.meta.env.PUBLIC_API_KEY;
const databaseUrl = import.meta.env.DATABASE_URL;
---

<html>
  <body>
    <h1>My Site</h1>
  </body>
</html>
Only variables prefixed with PUBLIC_ are available in client-side code. Server-only variables are accessible only during SSR.

.env Files

Store environment variables in .env files in your project root:
.env
# Public variables (exposed to client)
PUBLIC_API_URL=https://api.example.com
PUBLIC_SITE_NAME=My Awesome Site

# Private variables (server-only)
DATABASE_URL=postgresql://localhost:5432/mydb
API_SECRET_KEY=super-secret-key-do-not-share
EMAIL_PASSWORD=another-secret
Add .env files to .gitignore to avoid committing secrets to version control.

.env File Priority

Astro loads environment variables from multiple files in this order (highest priority first):
1

.env.production.local

Production environment, local overrides (gitignored)
2

.env.production

Production environment
3

.env.local

All environments, local overrides (gitignored)
4

.env

All environments
# .env - Default values for all environments
PUBLIC_API_URL=https://api.example.com

# .env.local - Local development overrides (gitignored)
PUBLIC_API_URL=http://localhost:3000

# .env.production - Production values
PUBLIC_API_URL=https://api.production.com
DATABASE_URL=postgresql://prod-server/db

Public vs Private Variables

Variables prefixed with PUBLIC_ are available everywhere:
.env
PUBLIC_API_URL=https://api.example.com
PUBLIC_ANALYTICS_ID=GA-123456
Accessible in any file:
src/components/Analytics.astro
<script>
  // Available in client-side code
  const analyticsId = import.meta.env.PUBLIC_ANALYTICS_ID;
  console.log('Analytics ID:', analyticsId);
</script>
Public variables are embedded in client bundles. Never use PUBLIC_ for secrets!

Type Safety

Type your environment variables for better IntelliSense and type checking:
src/env.d.ts
/// <reference types="astro/client" />

interface ImportMetaEnv {
  readonly DATABASE_URL: string;
  readonly API_SECRET_KEY: string;
  readonly PUBLIC_API_URL: string;
  readonly PUBLIC_SITE_NAME: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
Now TypeScript will:
  • Autocomplete environment variable names
  • Show type errors for missing variables
  • Catch typos at compile time
Make required variables non-optional in the type definition to catch missing values early.

Astro Environment Schema

For advanced type safety and validation, use Astro’s environment schema:
astro.config.mjs
import { defineConfig, envField } from 'astro/config';

export default defineConfig({
  env: {
    schema: {
      // Public variables
      PUBLIC_API_URL: envField.string({
        context: 'client',
        access: 'public',
        url: true
      }),
      
      PUBLIC_SITE_NAME: envField.string({
        context: 'client',
        access: 'public',
        default: 'My Site'
      }),

      // Server-only variables
      DATABASE_URL: envField.string({
        context: 'server',
        access: 'secret',
        url: true
      }),

      API_PORT: envField.number({
        context: 'server',
        access: 'public',
        default: 3000,
        min: 1,
        max: 65535
      }),

      ENABLE_ANALYTICS: envField.boolean({
        context: 'server',
        access: 'public',
        default: false
      }),

      LOG_LEVEL: envField.enum({
        context: 'server',
        access: 'public',
        values: ['debug', 'info', 'warn', 'error'],
        default: 'info'
      })
    }
  }
});

Field Types

envField.string({
  context: 'server',
  access: 'secret',
  default: 'default value',
  min: 5,          // Minimum length
  max: 100,        // Maximum length
  length: 10,      // Exact length
  url: true,       // Must be a valid URL
  includes: 'test', // Must include substring
  startsWith: 'https://',
  endsWith: '.com'
})
envField.number({
  context: 'server',
  access: 'public',
  default: 0,
  min: 0,          // Minimum value
  max: 100,        // Maximum value
  gt: 0,           // Greater than
  lt: 100,         // Less than
  int: true        // Must be integer
})
envField.boolean({
  context: 'server',
  access: 'public',
  default: false
})
envField.enum({
  context: 'server',
  access: 'public',
  values: ['development', 'staging', 'production'],
  default: 'development'
})

Access Levels

context
'client' | 'server'
required
Where the variable can be accessed
access
'public' | 'secret'
required
Whether the variable is public or contains secrets
Secret client variables are not allowed for security reasons. Secrets must be server-only.

Runtime Access

Access validated environment variables at runtime:
import { getEnv } from 'astro:env';

// Type-safe access
const apiUrl = getEnv('PUBLIC_API_URL');     // string
const port = getEnv('API_PORT');              // number
const analytics = getEnv('ENABLE_ANALYTICS'); // boolean
const logLevel = getEnv('LOG_LEVEL');         // 'debug' | 'info' | 'warn' | 'error'

Default Values

Provide fallback values for optional variables:
src/components/Config.astro
---
const apiUrl = import.meta.env.PUBLIC_API_URL ?? 'https://api.example.com';
const maxItems = parseInt(import.meta.env.PUBLIC_MAX_ITEMS ?? '10');
const debugMode = import.meta.env.PUBLIC_DEBUG === 'true';
---
Or use the schema’s default values:
astro.config.mjs
export default defineConfig({
  env: {
    schema: {
      PUBLIC_MAX_ITEMS: envField.number({
        context: 'client',
        access: 'public',
        default: 10
      })
    }
  }
});

Common Patterns

.env
PUBLIC_API_URL=https://api.example.com
API_KEY=secret-key-here
API_TIMEOUT=5000
src/lib/api.ts
const API_URL = import.meta.env.PUBLIC_API_URL;
const API_KEY = import.meta.env.API_KEY;
const TIMEOUT = parseInt(import.meta.env.API_TIMEOUT ?? '3000');

export async function fetchData() {
  const response = await fetch(`${API_URL}/data`, {
    headers: {
      'Authorization': `Bearer ${API_KEY}`
    },
    signal: AbortSignal.timeout(TIMEOUT)
  });

  return response.json();
}

Loading .env in Scripts

Load environment variables in Node.js scripts:
scripts/seed-db.ts
import { loadEnv } from 'vite';

const env = loadEnv('development', process.cwd(), '');
const databaseUrl = env.DATABASE_URL;

console.log('Connecting to:', databaseUrl);
// Seed database...

Platform-Specific Variables

Many hosting platforms provide their own environment variables:
VERCEL_ENV=production
VERCEL_URL=mysite.vercel.app
VERCEL_GIT_COMMIT_SHA=abc123
Access them like any other environment variable:
---
const isProd = import.meta.env.VERCEL_ENV === 'production';
const commitSha = import.meta.env.VERCEL_GIT_COMMIT_SHA;
---

Built-in Variables

Astro provides several built-in variables:
MODE
'development' | 'production'
Current mode (astro dev vs astro build)
PROD
boolean
Whether running in production
DEV
boolean
Whether running in development
SITE
string
The site URL from your config
BASE_URL
string
The base path from your config
---
const isDev = import.meta.env.DEV;
const siteUrl = import.meta.env.SITE;
---

{isDev && <DevTools />}
<link rel="canonical" href={`${siteUrl}${Astro.url.pathname}`} />

Security Best Practices

1

Never commit secrets

Add .env and .env.local to .gitignore:
.gitignore
.env
.env.local
.env.*.local
2

Use PUBLIC_ carefully

Only use PUBLIC_ for values safe to expose:
  • ✅ API endpoints
  • ✅ Public IDs
  • ❌ API keys
  • ❌ Passwords
  • ❌ Secrets
3

Provide example file

Create .env.example with dummy values:
.env.example
DATABASE_URL=postgresql://localhost:5432/mydb
API_SECRET_KEY=your-secret-key-here
PUBLIC_API_URL=https://api.example.com
4

Validate on startup

Check required variables exist:
src/lib/env.ts
const required = ['DATABASE_URL', 'API_SECRET_KEY'];

for (const key of required) {
  if (!import.meta.env[key]) {
    throw new Error(`Missing required env var: ${key}`);
  }
}

Configuration

Astro configuration options

TypeScript

TypeScript setup and types

Deployment

Deploy your Astro site

SSR

Server-side rendering

Build docs developers (and LLMs) love