Overview
FitAiid requires several environment variables for backend services, external APIs, and authentication. This guide explains each variable and how to obtain the necessary credentials.
Security Notice: Never commit .env files to Git. Always use platform-specific environment variable managers (Railway, Vercel) for production secrets.
Environment File Template
Use this template to create your .env file during local development:
backend/.env (Local Development)
Production (Railway)
# =============================================
# SERVER CONFIGURATION
# =============================================
PORT = 5000
NODE_ENV = development
# =============================================
# DATABASE - MONGODB ATLAS
# =============================================
MONGODB_URI = mongodb+srv://username:[email protected] /FitAiid? retryWrites = true & w = majority
# =============================================
# AUTHENTICATION - JWT
# =============================================
JWT_SECRET = your-super-secure-jwt-secret-minimum-32-characters-long
JWT_EXPIRE = 7d
# =============================================
# FRONTEND URLs
# =============================================
FRONTEND_URL = http://localhost:3000
FRONTEND_PROD_URL = https://fitaiid.vercel.app
# =============================================
# FIREBASE ADMIN SDK
# =============================================
FIREBASE_PROJECT_ID = your-project-id
FIREBASE_PRIVATE_KEY = -----BEGIN PRIVATE KEY----- \n YourKeyHere \n -----END PRIVATE KEY-----
FIREBASE_CLIENT_EMAIL = [email protected]
FIREBASE_DATABASE_URL = https://your-project.firebaseio.com
# =============================================
# OPENAI API (Workout Generation)
# =============================================
OPENAI_API_KEY = sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# =============================================
# GOOGLE OAUTH (Sign-in with Google)
# =============================================
GOOGLE_CLIENT_ID = your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET = your-google-oauth-secret
# =============================================
# STRIPE (Payment Processing)
# =============================================
STRIPE_PUBLIC_KEY = pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY = sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET = whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# =============================================
# EMAIL (Nodemailer)
# =============================================
EMAIL_SERVICE = gmail
EMAIL_USER = [email protected]
EMAIL_PASSWORD = your-gmail-app-password
EMAIL_FROM = [email protected]
# =============================================
# WEB PUSH NOTIFICATIONS (VAPID Keys)
# =============================================
VAPID_PUBLIC_KEY = BH5NRoA1tucvywFDHTef...
VAPID_PRIVATE_KEY = iYatNX1EcokCuw3ZNs4dg...
VAPID_EMAIL = mailto:[email protected]
# =============================================
# SENTRY (Error Tracking - Optional)
# =============================================
SENTRY_DSN = https://[email protected] /xxxxxxx
# =============================================
# LOGGING
# =============================================
LOG_LEVEL = debug
LOG_DIR = ./logs
# =============================================
# RATE LIMITING
# =============================================
RATE_LIMIT_WINDOW_MS = 900000
RATE_LIMIT_MAX_REQUESTS = 100
# =============================================
# CORS ORIGINS (comma-separated)
# =============================================
CORS_ORIGINS = http://localhost:3000,http://localhost:3001,https://fitaiid.vercel.app
Variable Reference
Server Configuration
Description: Port number for the Express serverDefault: 5000Usage: const PORT = process . env . PORT || 5000 ;
app . listen ( PORT );
Railway automatically assigns a port, but FitAiid defaults to 5000 if not specified.
Description: Application environment modeOptions: development | production | testUsage:
Controls logging verbosity
Enables/disables error stack traces
Affects database connection pooling
if ( process . env . NODE_ENV === 'development' ) {
console . log ( 'Debug information' );
}
Database Configuration
MONGODB_URI - MongoDB Atlas Connection String
Description: Complete connection string for MongoDB Atlas clusterFormat: How to Obtain:
Create MongoDB Atlas Account
Create Free Cluster
Click “Build a Database”
Select M0 (Free) tier
Choose a cloud provider and region
Name your cluster: Cluster0
Create Database User
Go to Database Access → Add New Database User
Choose Password authentication
Username: fitaiid_admin
Generate strong password
Database User Privileges: Atlas Admin
Whitelist IPs
Go to Network Access → Add IP Address
For Railway/production: 0.0.0.0/0 (all IPs)
For local dev: Click “Add Current IP Address”
Get Connection String
Go to Databases → Click “Connect”
Choose “Connect your application”
Driver: Node.js , Version: 4.1 or later
Copy the connection string:
mongodb+srv://fitaiid_admin:<password>@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority
Replace <password> with your actual password
Add /FitAiid before the ? to specify database name:
If your password contains special characters (@, :, /, etc.), you must URL-encode them:
Authentication & Security
Description: Secret key for signing JSON Web TokensRequirements:
Minimum 32 characters
Use random, unpredictable string
Never share or commit to Git
Generate: # Option 1: OpenSSL
openssl rand -base64 32
# Option 2: Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Example output:
# TechStore_Super_Secret_Key_2025_abcdef123456
Usage: const token = jwt . sign ({ userId: user . _id }, process . env . JWT_SECRET , {
expiresIn: process . env . JWT_EXPIRE
});
Description: Token expiration timeFormat: String with units (7d, 24h, 60m, 3600s)Recommended:
Development: 7d (7 days)
Production: 24h (24 hours)
High-security: 15m (15 minutes with refresh tokens)
Example:
Firebase Admin SDK
Firebase Configuration - Complete Setup
Description: Firebase Admin SDK credentials for server-side authenticationHow to Obtain:
Create Firebase Project
Go to Firebase Console
Click “Add Project”
Name: FitAiid
Enable Google Analytics (optional)
Generate Service Account Key
Go to Project Settings (gear icon) → Service Accounts
Click “Generate New Private Key”
Confirm and download the JSON file
IMPORTANT: Never commit this file to Git
Extract Credentials
Open the downloaded JSON file and extract these values: {
"type" : "service_account" ,
"project_id" : "fitaiid-12345" ,
"private_key_id" : "abc123..." ,
"private_key" : "-----BEGIN PRIVATE KEY----- \n MIIE... \n -----END PRIVATE KEY----- \n " ,
"client_email" : "[email protected] " ,
"client_id" : "123456789" ,
"auth_uri" : "https://accounts.google.com/o/oauth2/auth" ,
"token_uri" : "https://oauth2.googleapis.com/token" ,
"auth_provider_x509_cert_url" : "https://www.googleapis.com/oauth2/v1/certs" ,
"client_x509_cert_url" : "https://www.googleapis.com/robot/v1/..."
}
Configure Environment Variables
Option 1: Individual Variables (Local Dev) FIREBASE_PROJECT_ID = fitaiid-12345
FIREBASE_PRIVATE_KEY = -----BEGIN PRIVATE KEY----- \n MIIE... \n -----END PRIVATE KEY-----
FIREBASE_CLIENT_EMAIL = [email protected]
Option 2: Full JSON (Railway/Production) FIREBASE_ADMIN_SDK = { "type" : "service_account" , "project_id" : "fitaiid-12345" ,...}
Initialize in Code
const admin = require ( 'firebase-admin' );
// Option 1: From individual env vars
admin . initializeApp ({
credential: admin . credential . cert ({
projectId: process . env . FIREBASE_PROJECT_ID ,
privateKey: process . env . FIREBASE_PRIVATE_KEY . replace ( / \\ n/ g , ' \n ' ),
clientEmail: process . env . FIREBASE_CLIENT_EMAIL
})
});
// Option 2: From JSON string
const serviceAccount = JSON . parse ( process . env . FIREBASE_ADMIN_SDK );
admin . initializeApp ({
credential: admin . credential . cert ( serviceAccount )
});
The private key contains newline characters (\n). In Railway/Vercel, paste the entire JSON as one line. In local .env, escape newlines properly.
External APIs
OPENAI_API_KEY - AI Workout Generation
Description: OpenAI API key for generating personalized workout routinesHow to Obtain:
Add Payment Method
Go to Billing → Add payment method (required for API access)
Create API Key
Go to API Keys
Click “Create new secret key”
Name: FitAiid Production
Copy the key immediately (you won’t see it again)
Format: OPENAI_API_KEY = sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Usage in Code: const { OpenAI } = require ( 'openai' );
const openai = new OpenAI ({
apiKey: process . env . OPENAI_API_KEY
});
const completion = await openai . chat . completions . create ({
model: "gpt-4" ,
messages: [{ role: "user" , content: "Generate a workout plan..." }]
});
Pricing:
GPT-3.5 Turbo: ~$0.002 per 1K tokens
GPT-4: ~$0.03 per 1K tokens
Start with GPT-3.5 Turbo for cost-effective testing, upgrade to GPT-4 for better workout generation quality.
STRIPE API Keys - Payment Processing
Description: Stripe API keys for handling subscriptions and paymentsHow to Obtain:
Get API Keys
Go to API Keys
Note your Publishable key (starts with pk_)
Click “Reveal test key” to see Secret key (starts with sk_)
Create Webhook
Go to Webhooks
Click “Add endpoint”
Endpoint URL: https://your-api.railway.app/api/webhooks/stripe
Events to listen: checkout.session.completed, payment_intent.succeeded
Copy the Signing secret (starts with whsec_)
Environment Variables: STRIPE_PUBLIC_KEY = pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY = sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET = whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Usage: const stripe = require ( 'stripe' )( process . env . STRIPE_SECRET_KEY );
const session = await stripe . checkout . sessions . create ({
payment_method_types: [ 'card' ],
line_items: [{
price_data: {
currency: 'usd' ,
product_data: { name: 'Premium Subscription' },
unit_amount: 2999 // $29.99
},
quantity: 1
}],
mode: 'subscription' ,
success_url: 'https://fitaiid.com/success' ,
cancel_url: 'https://fitaiid.com/cancel'
});
Test vs Production Keys:
Development: Use pk_test_ and sk_test_ keys
Production: Switch to pk_live_ and sk_live_ keys
Never commit live keys to Git
EMAIL Configuration - Nodemailer with Gmail
Description: Gmail SMTP credentials for sending emails (password resets, notifications)How to Obtain App Password:
Enable 2-Factor Authentication
Generate App Password
Go to App Passwords
Select app: Mail
Select device: Other (Custom name)
Enter name: FitAiid Backend
Click Generate
Copy the 16-character password (spaces will be removed)
Environment Variables: Usage: const nodemailer = require ( 'nodemailer' );
const transporter = nodemailer . createTransport ({
service: process . env . EMAIL_SERVICE ,
auth: {
user: process . env . EMAIL_USER ,
pass: process . env . EMAIL_PASSWORD
}
});
await transporter . sendMail ({
from: process . env . EMAIL_FROM ,
to: user . email ,
subject: 'Welcome to FitAiid!' ,
html: '<h1>Welcome!</h1>'
});
For production, consider using a dedicated email service like SendGrid or AWS SES for better deliverability and analytics.
VAPID Keys - Web Push Notifications
Description: VAPID (Voluntary Application Server Identification) keys for sending push notificationsGenerate VAPID Keys: # Install web-push globally
npm install -g web-push
# Generate VAPID keys
web-push generate-vapid-keys
Output: =======================================
Public Key:
BH5NRoA1tucvywFDHTef...
Private Key:
iYatNX1EcokCuw3ZNs4dg...
=======================================
Environment Variables: VAPID_PUBLIC_KEY = BH5NRoA1tucvywFDHTef...
VAPID_PRIVATE_KEY = iYatNX1EcokCuw3ZNs4dg...
VAPID_EMAIL = mailto:[email protected]
Usage (Backend): const webpush = require ( 'web-push' );
webpush . setVapidDetails (
process . env . VAPID_EMAIL ,
process . env . VAPID_PUBLIC_KEY ,
process . env . VAPID_PRIVATE_KEY
);
await webpush . sendNotification ( subscription , JSON . stringify ({
title: 'Workout Reminder' ,
body: 'Time for your leg day workout!' ,
icon: '/img/icon-192.png'
}));
Usage (Frontend): // Subscribe to push notifications
const registration = await navigator . serviceWorker . ready ;
const subscription = await registration . pushManager . subscribe ({
userVisibleOnly: true ,
applicationServerKey: 'BH5NRoA1tucvywFDHTef...' // VAPID_PUBLIC_KEY
});
VAPID keys are unique to your application. Generate once and use the same keys across all environments.
Optional Services
SENTRY_DSN - Error Tracking (Optional)
Description: Sentry DSN for error monitoring and trackingHow to Obtain:
Create Project
Click “Create Project”
Platform: Node.js
Name: FitAiid Backend
Get DSN
Copy the DSN from the setup page: Environment Variable: Usage: const Sentry = require ( '@sentry/node' );
Sentry . init ({ dsn: process . env . SENTRY_DSN });
// Capture exceptions
try {
// your code
} catch ( error ) {
Sentry . captureException ( error );
}
Sentry’s free tier includes 5K errors/month, perfect for staging environments.
Railway Configuration
Add all environment variables in Railway Dashboard:
Open Railway Project
Navigate to your deployed backend project
Variables Tab
Click on the Variables tab
Add Each Variable
Click “New Variable” and add:
Variable name (e.g., MONGODB_URI)
Variable value
Click “Add”
Repeat for all 20+ variables
Redeploy
Railway automatically redeploys when variables are added/changed
For FIREBASE_ADMIN_SDK, paste the entire JSON object as a single-line string (remove all newlines within the JSON).
Vercel Configuration
Vercel only needs the backend API URL:
VITE_API_URL = https://fitaiid-api.railway.app
Project Settings
Go to Vercel project → Settings → Environment Variables
Add Variable
Key: VITE_API_URL
Value: Your Railway backend URL
Environment: Production, Preview, Development
Redeploy
Trigger a new deployment to apply changes
Security Best Practices
Never Commit Secrets Add .env to .gitignore to prevent accidental commits of sensitive data.
Use Strong Secrets Generate cryptographically random secrets with minimum 32 characters.
Rotate Keys Regularly Change API keys and secrets every 90 days, especially after team member changes.
Use Environment-Specific Keys Use test keys for development, production keys only in production.
Validation Checklist
Before deploying, verify all variables are set:
Local Development
# Test locally first
npm run dev
# Verify logs show:
# ✅ MongoDB Atlas connected
# ✅ Server running on port 5000
Railway Production
Check Railway deployment logs for:
✅ All variables loaded
✅ No “undefined” errors
✅ MongoDB connected
✅ Server started successfully
Test API Endpoints
# Test authentication
curl https://fitaiid-api.railway.app/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected] ","password":"Admin1234"}'
# Should return JWT token
Troubleshooting
Symptom: process.env.VARIABLE_NAME is undefinedCauses:
Variable not added to Railway
Typo in variable name
Railway not redeployed after adding variable
Solution:
Double-check variable exists in Railway Variables tab
Verify exact spelling (case-sensitive)
Click “Redeploy” in Railway
Symptom: MongoNetworkError: connection timed outCauses:
IP not whitelisted in MongoDB Atlas
Incorrect connection string
Special characters not URL-encoded
Solution:
Add 0.0.0.0/0 to MongoDB Atlas Network Access
Verify connection string format
URL-encode special characters in password
Firebase authentication fails
Symptom: Error: Firebase credential errorCauses:
Invalid JSON format in FIREBASE_ADMIN_SDK
Newlines not properly escaped
Missing quotes in JSON
Solution:
Copy entire JSON from Firebase console
Remove all newlines and extra spaces
Ensure valid JSON syntax (use JSONLint to validate)
Environment Variables Summary
Variable Required Service Notes PORTYes Server Default: 5000 NODE_ENVYes Server production/development MONGODB_URIYes Database MongoDB Atlas connection JWT_SECRETYes Auth Min 32 chars JWT_EXPIREYes Auth e.g., 24h, 7d FIREBASE_ADMIN_SDKYes Auth Full JSON or individual vars OPENAI_API_KEYYes AI Starts with sk-proj- STRIPE_SECRET_KEYYes Payments Starts with sk_ STRIPE_WEBHOOK_SECRETYes Payments Starts with whsec_ EMAIL_USERYes Email Gmail address EMAIL_PASSWORDYes Email Gmail app password VAPID_PUBLIC_KEYYes Push Web Push public key VAPID_PRIVATE_KEYYes Push Web Push private key VAPID_EMAILYes Push mailto:email@domain CORS_ORIGINSYes Security Comma-separated URLs SENTRY_DSNNo Monitoring Optional error tracking
Next Steps
With all environment variables configured, your deployment is complete!
Back to Deployment Overview Review the complete deployment architecture and verify your setup.