Skip to main content
Environment variables allow you to configure different settings for development, production, and testing environments without modifying code or duplicating configuration files.

What are Environment Variables?

Environment variables are configuration values that change based on where your server is running:

Development

dev - Local testing with verbose logging and hot reload

Production

prod - Live server with optimized performance and minimal logging

Testing

test - Automated testing environment with mock data

Setting the Environment

The primary environment variable is environment:
# server.cfg
set environment "prod"
Valid Values:
  • dev - Development
  • prod - Production
  • test - Testing
Important: Change this to "prod" before launching your live server! Development mode has performance impacts and verbose logging.

Environment-Specific Behavior

Mythic Framework changes behavior based on the environment:

Development Environment

set environment "dev"
Characteristics:
  • ✅ Verbose console logging
  • ✅ Database query logging
  • ✅ Event monitoring/debugging
  • ✅ Performance profiling enabled
  • ✅ Hot reload for Lua changes
  • ✅ React DevTools enabled in UIs
  • ✅ Detailed error stack traces
  • ✅ Relaxed security (for testing)
  • ❌ Lower performance
  • ❌ Larger log files
Use Cases:
  • Local development
  • Feature testing
  • Debugging issues
  • Learning the framework
Development-Only Features:
-- mythic-base checks environment
if GetConvar('environment', 'prod') == 'dev' then
    -- Enable debug logging
    COMPONENTS.Logger:SetLevel('debug')

    -- Log all database queries
    COMPONENTS.Database:EnableQueryLogging(true)

    -- Log all events
    COMPONENTS.Events:EnableMonitoring(true)
end

Production Environment

set environment "prod"
Characteristics:
  • ✅ Optimized performance
  • ✅ Minimal logging (errors only)
  • ✅ Security features enabled
  • ✅ Anti-cheat active
  • ✅ Compressed assets
  • ✅ Database connection pooling
  • ❌ No verbose debugging
  • ❌ No development tools
Use Cases:
  • Live public server
  • Final testing before launch
  • Maximum performance needed
Production Optimizations:
if GetConvar('environment', 'prod') == 'prod' then
    -- Minimal logging
    COMPONENTS.Logger:SetLevel('error')

    -- Disable query logging
    COMPONENTS.Database:EnableQueryLogging(false)

    -- Enable all security features
    COMPONENTS.AntiCheat:Enable(true)

    -- Use compressed UI assets
    COMPONENTS.UI:UseMinified(true)
end

Testing Environment

set environment "test"
Characteristics:
  • ✅ Mock data enabled
  • ✅ Automated testing support
  • ✅ Fast reset/cleanup
  • ✅ Isolated test database
  • ✅ Deterministic behavior
  • ✅ Performance profiling
Use Cases:
  • Automated tests
  • Integration testing
  • Performance benchmarking
  • Feature testing with mock data

Common Environment Variables

Debug Mode

# Enable/disable debug output
set debug_mode "false"
Values: "true" or "false" Effect:
  • Logs all function calls
  • Prints component registrations
  • Shows event triggers
  • Database query logging
  • Network event monitoring
When to Use:
  • Troubleshooting issues
  • Understanding code flow
  • Debugging new features
Performance Impact: Debug mode significantly increases log output and CPU usage. Never enable in production!

Database Debugging

# Log all database queries
set database_debug "false"
Values: "true" or "false" Example Output:
[Database] Query: SELECT * FROM characters WHERE SID = ?
[Database] Params: [1]
[Database] Time: 2.3ms
[Database] Result: 1 rows

Verbose Logging

# Set logging level
set log_level "info"
Values:
  • "debug" - Everything (very verbose)
  • "info" - Informational messages
  • "warn" - Warnings only
  • "error" - Errors only
  • "none" - No logging
Recommendation:
  • Development: "debug" or "info"
  • Production: "error" or "warn"

UI Development Mode

# Enable React DevTools and hot reload
set ui_dev_mode "false"
Values: "true" or "false" Effect:
  • Enables React DevTools in browser
  • Hot reload for UI changes
  • Unminified JavaScript
  • Source maps enabled
  • Detailed error messages

Database Configuration

# Separate databases per environment
set mongodb_database "mythic_${environment}"
Result:
  • Development: mythic_dev
  • Production: mythic_prod
  • Testing: mythic_test
Benefits:
  • Isolated data per environment
  • Safe development testing
  • No risk of corrupting production data

Environment-Based Configuration

Conditional Loading in server.cfg

# Load different configs based on environment

# Development
if [[ "${environment}" == "dev" ]]; then
    set debug_mode "true"
    set log_level "debug"
    set ui_dev_mode "true"
    set database_debug "true"

    # Use dev database
    set mongodb_database "mythic_dev"
    set mysql_connection_string "mysql://root:password@localhost/mythic_dev"

    # Load development resources
    ensure mythic-dev-tools
    ensure mythic-debug
fi

# Production
if [[ "${environment}" == "prod" ]]; then
    set debug_mode "false"
    set log_level "error"
    set ui_dev_mode "false"
    set database_debug "false"

    # Use production database
    set mongodb_database "mythic"
    set mysql_connection_string "mysql://mythic_user:secure_pass@localhost/mythic"

    # Don't load dev resources
fi

# Testing
if [[ "${environment}" == "test" ]]; then
    set debug_mode "true"
    set log_level "info"

    # Use test database
    set mongodb_database "mythic_test"
    set mysql_connection_string "mysql://root:password@localhost/mythic_test"

    # Load testing framework
    ensure mythic-test-framework
fi

Reading Environment in Code

-- Get environment
local env = GetConvar('environment', 'prod')

if env == 'dev' then
    -- Development-specific code
    print('[DEV] Debug mode enabled')
elseif env == 'prod' then
    -- Production-specific code
    print('[PROD] Production mode')
elseif env == 'test' then
    -- Testing-specific code
    print('[TEST] Test mode')
end

-- Check debug mode
local debugMode = GetConvar('debug_mode', 'false') == 'true'

if debugMode then
    print('[DEBUG] This is a debug message')
end

-- Get log level
local logLevel = GetConvar('log_level', 'info')

-- Use in logging
if logLevel == 'debug' then
    print('[DEBUG] Detailed information')
end

Custom Environment Variables

Create your own environment variables for resource-specific configuration:
# server.cfg

# Custom feature flags
set feature_new_inventory "false"
set feature_experimental_racing "false"

# Resource-specific settings
set inventory_max_slots "50"
set vehicle_fuel_consumption "1.0"

# API keys (use env vars for security)
set external_api_key "your_api_key_here"

# Discord configuration
set discord_server_id "123456789"
set discord_bot_token "your_bot_token"
Reading Custom Variables:
-- Get custom variables
local maxSlots = tonumber(GetConvar('inventory_max_slots', '50'))
local fuelRate = tonumber(GetConvar('vehicle_fuel_consumption', '1.0'))

-- Feature flags
local newInventoryEnabled = GetConvar('feature_new_inventory', 'false') == 'true'

if newInventoryEnabled then
    print('[INFO] New inventory system enabled')
    -- Load new system
else
    -- Load old system
end

Best Practices

For better organization, use environment files:Create .env file:
# .env
ENVIRONMENT=dev
DEBUG_MODE=true
LOG_LEVEL=debug
MONGODB_URL=mongodb://localhost:27017/mythic_dev
MYSQL_URL=mysql://root:password@localhost/mythic_dev
Load in server.cfg:
# Load variables from .env
exec .env

# Use variables
set environment "${ENVIRONMENT}"
set debug_mode "${DEBUG_MODE}"
set log_level "${LOG_LEVEL}"
Add to .gitignore:
.env
.env.local
*.env
❌ Bad:
local apiKey = "sk_live_123456789abcdef"  -- Hardcoded!
✅ Good:
local apiKey = GetConvar('external_api_key', '')
if apiKey == '' then
    error('API key not configured!')
end
Benefits:
  • Secrets not in code
  • Can’t accidentally commit to git
  • Different keys per environment
Create docs/environment-variables.md:
# Environment Variables

## Required Variables

| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| environment | string | prod | Server environment (dev/prod/test) |
| debug_mode | boolean | false | Enable debug logging |
| mongodb_url | string | - | MongoDB connection string |
| mysql_connection_string | string | - | MySQL connection string |

## Optional Variables

| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| log_level | string | info | Logging level (debug/info/warn/error) |
| ui_dev_mode | boolean | false | Enable React DevTools |
| feature_new_inventory | boolean | false | Enable new inventory system |
Validate environment variables on server start:
-- mythic-base/server/validation.lua

local function ValidateEnvironment()
    local env = GetConvar('environment', '')

    -- Validate environment is set
    if env == '' then
        error('[ERROR] Environment not set! Add "set environment" to server.cfg')
    end

    -- Validate environment is valid
    local validEnvs = { dev = true, prod = true, test = true }
    if not validEnvs[env] then
        error('[ERROR] Invalid environment: ' .. env)
    end

    -- Validate database URLs in production
    if env == 'prod' then
        local mongoUrl = GetConvar('mongodb_url', '')
        if mongoUrl == '' then
            error('[ERROR] MongoDB URL not configured!')
        end

        -- Warn if using default passwords
        if string.find(mongoUrl, 'password') then
            print('[WARNING] Using default database password in production!')
        end
    end

    print('[✓] Environment validated: ' .. env)
end

AddEventHandler('onServerResourceStart', function(resourceName)
    if resourceName == 'mythic-base' then
        ValidateEnvironment()
    end
end)
Set sensible defaults per environment:
local env = GetConvar('environment', 'prod')

-- Environment-specific defaults
local defaults = {
    dev = {
        logLevel = 'debug',
        debugMode = true,
        maxPlayers = 8,
        saveInterval = 60000  -- 1 minute
    },
    prod = {
        logLevel = 'error',
        debugMode = false,
        maxPlayers = 128,
        saveInterval = 300000  -- 5 minutes
    },
    test = {
        logLevel = 'info',
        debugMode = true,
        maxPlayers = 4,
        saveInterval = 10000  -- 10 seconds
    }
}

-- Get config with fallback to defaults
local config = defaults[env] or defaults.prod

-- Use config
COMPONENTS.Logger:SetLevel(GetConvar('log_level', config.logLevel))
local debugMode = GetConvar('debug_mode', tostring(config.debugMode)) == 'true'

Multiple Environment Setup

Manage multiple environments (local dev, staging, production):

Directory Structure

MythicFramework/
├── server.cfg                  # Base configuration
├── configs/
│   ├── dev.cfg                # Development overrides
│   ├── staging.cfg            # Staging overrides
│   └── prod.cfg               # Production overrides
└── resources/

Base server.cfg

# server.cfg (shared settings)

sv_hostname "Mythic Roleplay"
sv_maxclients 128
sv_enforceGameBuild 2802

# Load environment-specific config
exec configs/${SERVER_ENV}.cfg

# Load resources
exec configs/resources.cfg

Environment Configs

# configs/dev.cfg
set environment "dev"
set debug_mode "true"
set log_level "debug"
set ui_dev_mode "true"

# Development database
set mongodb_url "mongodb://localhost:27017/mythic_dev"
set mysql_connection_string "mysql://root:dev_password@localhost/mythic_dev"

# Development webhooks (different Discord channel)
set discord_admin_webhook "https://discord.com/api/webhooks/DEV_WEBHOOK"

# Load dev resources
ensure mythic-dev-tools

Launch Scripts

#!/bin/bash
export SERVER_ENV=dev
./FXServer +exec server.cfg

Troubleshooting

Problem: GetConvar returns empty stringSolutions:
  1. Check variable is set in server.cfg:
    set my_variable "value"
    
  2. Verify syntax (needs set):
    # ❌ Wrong
    my_variable "value"
    
    # ✅ Correct
    set my_variable "value"
    
  3. Check for typos in variable name
  4. Ensure server.cfg was loaded
  5. Use default fallback:
    local value = GetConvar('my_variable', 'default_value')
    
Problem: Boolean variables don’t work as expectedCause: GetConvar returns strings, not booleansSolution:
-- ❌ Wrong - always true!
local debug = GetConvar('debug_mode', 'false')
if debug then  -- This is always true (non-empty string)
    print('Debug mode')
end

-- ✅ Correct - compare string
local debug = GetConvar('debug_mode', 'false') == 'true'
if debug then
    print('Debug mode')
end

-- ✅ Alternative - helper function
local function getBoolConvar(name, default)
    return GetConvar(name, tostring(default)) == 'true'
end

local debug = getBoolConvar('debug_mode', false)
Problem: Math operations fail on convarsCause: GetConvar returns stringsSolution:
-- ❌ Wrong - string concatenation!
local maxSlots = GetConvar('max_slots', '50')
local doubleSlots = maxSlots * 2  -- NaN or unexpected

-- ✅ Correct - convert to number
local maxSlots = tonumber(GetConvar('max_slots', '50'))
local doubleSlots = maxSlots * 2

-- ✅ With validation
local maxSlots = tonumber(GetConvar('max_slots', '50')) or 50
if maxSlots < 1 or maxSlots > 100 then
    maxSlots = 50
end

Next Steps

Pro Tip: Create separate server.cfg files for each environment (server-dev.cfg, server-prod.cfg) and use startup scripts to select which one to load. This prevents accidentally starting production with development settings.