Jet uses @ngx-env/builder for type-safe environment variable management across different environments.
Environment Variables
Configuration File
Environment variables are defined in .env files:
# .env.example
NG_APP_GOOGLE_ANALYTICS_MEASUREMENT_ID = your-google-analytics-measurement-id
NG_APP_IS_ANALYTICS_ENABLED = false
NG_APP_IS_LOGGING_ENABLED = true
NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY = your-supabase-publishable-or-anon-key
NG_APP_SUPABASE_URL = http://localhost:54321
Never commit .env files to version control. Add them to .gitignore.
Setting Up Your Environment
Update values
Edit .env with your actual values: NG_APP_SUPABASE_URL = https://your-project.supabase.co
NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY = your-actual-key
NG_APP_IS_ANALYTICS_ENABLED = true
NG_APP_GOOGLE_ANALYTICS_MEASUREMENT_ID = G-XXXXXXXXXX
Restart the dev server
Environment variables are loaded at build time, so restart your dev server:
Available Environment Variables
Supabase Configuration
Your Supabase project URL.
Local development : http://localhost:54321
Production : https://your-project.supabase.co
NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY
Your Supabase anon/public key (safe to expose in client-side code).
Analytics Configuration
NG_APP_GOOGLE_ANALYTICS_MEASUREMENT_ID
Your Google Analytics 4 Measurement ID (format: G-XXXXXXXXXX).
NG_APP_IS_ANALYTICS_ENABLED
Enable or disable Google Analytics tracking.
Set to false in development
Set to true in production
Developer Configuration
NG_APP_IS_LOGGING_ENABLED
Enable or disable console logging throughout the application.
Set to true in development for debugging
Set to false in production to reduce console noise
Using Environment Variables
In TypeScript
Access environment variables using the global import.meta.env object:
const supabaseUrl = import . meta . env [ 'NG_APP_SUPABASE_URL' ];
const supabaseKey = import . meta . env [ 'NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY' ];
const isAnalyticsEnabled = import . meta . env [ 'NG_APP_IS_ANALYTICS_ENABLED' ] === 'true' ;
With Injection Tokens
Jet uses Angular injection tokens for type-safe environment variable access:
// injection-tokens/supabase-client.injection-token.ts
import { inject , InjectionToken } from '@angular/core' ;
import { createClient , SupabaseClient } from '@supabase/supabase-js' ;
export const SUPABASE_CLIENT = new InjectionToken < SupabaseClient >(
'SUPABASE_CLIENT' ,
{
providedIn: 'root' ,
factory : () =>
createClient (
import . meta . env [ 'NG_APP_SUPABASE_URL' ],
import . meta . env [ 'NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY' ]
),
}
);
Using in components/services:
import { inject } from '@angular/core' ;
import { SUPABASE_CLIENT } from '@jet/injection-tokens/supabase-client.injection-token' ;
export class ProfileService {
readonly #supabase = inject ( SUPABASE_CLIENT );
async getProfile ( userId : string ) {
return this . #supabase
. from ( 'profiles' )
. select ( '*' )
. eq ( 'id' , userId )
. single ();
}
}
Boolean Environment Variables
Environment variables are always strings. Convert to boolean:
// is-analytics-enabled.injection-token.ts
import { InjectionToken } from '@angular/core' ;
export const IS_ANALYTICS_ENABLED = new InjectionToken < boolean >(
'IS_ANALYTICS_ENABLED' ,
{
providedIn: 'root' ,
factory : () => import . meta . env [ 'NG_APP_IS_ANALYTICS_ENABLED' ] === 'true' ,
}
);
Multiple Environments
Creating Environment-Specific Files
Create separate .env files for different environments:
.env # Default/development
.env.local # Local overrides (gitignored)
.env.production # Production
.env.staging # Staging
Environment File Priority
@ngx-env/builder loads files in this order (later files override earlier ones):
.env
.env.local
.env.[environment]
.env.[environment].local
Using Different Environments
Development
Production
Custom Environment
ng serve
# or
ng build --configuration development
Loads .env and .env.local ng build --configuration production
Loads .env, .env.local, .env.production, and .env.production.local Create a custom configuration in angular.json, then: ng build --configuration staging
Adding New Environment Variables
Add to .env.example
Document the new variable: # .env.example
NG_APP_API_BASE_URL = https://api.example.com
NG_APP_FEATURE_FLAG_NEW_UI = false
Add to your .env file
# .env
NG_APP_API_BASE_URL = http://localhost:3000
NG_APP_FEATURE_FLAG_NEW_UI = true
Create an injection token (optional)
// injection-tokens/api-base-url.injection-token.ts
import { InjectionToken } from '@angular/core' ;
export const API_BASE_URL = new InjectionToken < string >(
'API_BASE_URL' ,
{
providedIn: 'root' ,
factory : () => import . meta . env [ 'NG_APP_API_BASE_URL' ] || 'https://api.example.com' ,
}
);
Use in your code
import { inject } from '@angular/core' ;
import { API_BASE_URL } from '@jet/injection-tokens/api-base-url.injection-token' ;
export class ApiService {
readonly #baseUrl = inject ( API_BASE_URL );
getUsers () {
return fetch ( ` ${ this . #baseUrl } /users` );
}
}
Environment Variable Naming
All environment variables must be prefixed with NG_APP_ to be available in your Angular app.
Naming Conventions
Prefix : Always use NG_APP_ prefix
Case : Use UPPER_SNAKE_CASE
Descriptive : Use clear, descriptive names
# Good
NG_APP_SUPABASE_URL = ...
NG_APP_IS_ANALYTICS_ENABLED = ...
NG_APP_MAX_FILE_SIZE_MB = ...
# Bad (no prefix)
SUPABASE_URL = ...
# Bad (unclear)
NG_APP_URL = ...
NG_APP_KEY = ...
Security Best Practices
Add .env files to .gitignore: # .gitignore
.env
.env.local
.env*.local
Only commit .env.example with placeholder values.
Use different keys per environment
Never use production keys in development: # .env (development)
NG_APP_SUPABASE_URL = http://localhost:54321
# .env.production
NG_APP_SUPABASE_URL = https://prod.supabase.co
Validate required variables
Check for required variables at app startup: export function validateEnvironment () {
const required = [
'NG_APP_SUPABASE_URL' ,
'NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY'
];
for ( const key of required ) {
if ( ! import . meta . env [ key ]) {
throw new Error ( `Missing required environment variable: ${ key } ` );
}
}
}
Only expose public keys client-side
Client-side environment variables are public. Never include:
Private API keys
Service account credentials
Database passwords
OAuth client secrets
These should only exist server-side or in Supabase Edge Functions.
Vercel
Set environment variables in Vercel dashboard:
Go to Project Settings → Environment Variables
Add variables (without NG_APP_ in the Vercel UI)
Vercel automatically prefixes them for Angular
Alternatively, use Vercel CLI:
vercel env add NG_APP_SUPABASE_URL
For other platforms (Netlify, AWS, etc.), set environment variables in their respective dashboards or CLI tools.
Debugging Environment Variables
To see loaded environment variables during build:
// In any component (temporarily)
console . log ( 'Environment:' , import . meta . env );
Or create a debug endpoint:
// Only in development!
if ( import . meta . env [ 'NG_APP_IS_LOGGING_ENABLED' ] === 'true' ) {
console . log ( 'Loaded environment variables:' , {
supabaseUrl: import . meta . env [ 'NG_APP_SUPABASE_URL' ],
analyticsEnabled: import . meta . env [ 'NG_APP_IS_ANALYTICS_ENABLED' ],
loggingEnabled: import . meta . env [ 'NG_APP_IS_LOGGING_ENABLED' ],
});
}