Skip to main content

Environment Variables & Configuration

Learn how to configure your applications using environment variables, secrets, and runtime configuration.

Environment Variable Types

The Strongly platform supports three types of environment variables:

  1. Regular Variables: Standard configuration values
  2. Secrets: Encrypted sensitive data (passwords, API keys)
  3. Build-time Variables: Values injected during Docker build

Defining Variables in Manifest

Regular Environment Variables

Standard configuration values accessible at runtime:

env:
- name: API_URL
value: "https://api.example.com"
required: false
description: Backend API endpoint

- name: LOG_LEVEL
value: "info"
required: false
description: Application log level (debug, info, warn, error)

Secrets

Sensitive data stored as Kubernetes Secrets and encrypted at rest:

env:
- name: DATABASE_PASSWORD
value: "" # Provided by user during deployment
required: true
secret: true
description: PostgreSQL database password

- name: JWT_SECRET
value: ""
required: true
secret: true
description: Secret for JWT token signing

- name: API_KEY
value: ""
required: true
secret: true
description: Third-party API key
Security Best Practices
  • Never commit secrets to version control
  • Always mark sensitive values with secret: true
  • Leave value empty for secrets - users provide them during deployment
  • Rotate secrets regularly

Build-time Variables

Values passed to Docker build as --build-arg:

env:
- name: NODE_ENV
value: "production"
buildtime: true
description: Node.js environment

- name: REACT_APP_VERSION
value: "1.0.0"
buildtime: true
description: Application version displayed in UI

- name: REACT_APP_API_URL
value: "https://api.acme.com"
buildtime: true
description: Baked into React build

Using in Dockerfile:

ARG NODE_ENV
ARG REACT_APP_VERSION
ARG REACT_APP_API_URL

ENV NODE_ENV=${NODE_ENV}
ENV REACT_APP_VERSION=${REACT_APP_VERSION}
ENV REACT_APP_API_URL=${REACT_APP_API_URL}

RUN npm run build

Variable Precedence

Environment variables can come from multiple sources. The platform applies them in this order (last wins):

  1. Manifest defaults (strongly.manifest.yaml)
  2. Platform injected (STRONGLY_SERVICES, etc.)
  3. User provided (during deployment)
  4. .env file (if included in archive)

Platform-Injected Variables

The platform automatically injects these variables into all app pods:

Core Platform Variables

VariableDescriptionExample
STRONGLY_URLCritical for frontend apps. Full proxy URL for API callshttp://localhost:3000/api/proxy/app-xyz123
STRONGLY_HOSTPlatform host URLhttp://localhost:3000
STRONGLY_APP_IDUnique app identifierapp-xyz123
STRONGLY_SERVICESJSON with all connected servicesSee below

STRONGLY_URL (Critical for Frontend Apps)

When your app is displayed in the platform's iframe, frontend code needs to make API calls through the proxy. STRONGLY_URL provides the correct base URL.

Why this matters: Apps are accessed via /apps/app-xyz/view. Without STRONGLY_URL:

  • ❌ API calls go to http://localhost:3000/api/... (wrong - hits the platform, not your app)
  • ✅ With STRONGLY_URL, API calls go to http://localhost:3000/api/proxy/app-xyz/api/... (correct - proxied to your app)

Server-side: Inject runtime config into HTML

// In your Express server's static file handler
app.get('*', (req, res) => {
const indexPath = path.join(__dirname, '../client/dist/index.html');
fs.readFile(indexPath, 'utf8', (err, data) => {
if (err) return res.status(500).send('Server error');

// Build runtime config from platform environment variables
const runtimeConfig = {
STRONGLY_URL: process.env.STRONGLY_URL || '',
STRONGLY_HOST: process.env.STRONGLY_HOST || '',
STRONGLY_APP_ID: process.env.STRONGLY_APP_ID || '',
API_URL: '/api'
};

// Inject into HTML
const modifiedHtml = data.replace(
'</head>',
`<script>window.__RUNTIME_CONFIG__ = ${JSON.stringify(runtimeConfig)};</script></head>`
);

res.send(modifiedHtml);
});
});

Client-side: Use runtime config for API calls

// In your API service (e.g., api.ts)
function getApiBaseUrl() {
const config = window.__RUNTIME_CONFIG__ || {};
if (config.STRONGLY_URL) {
// STRONGLY_URL = http://localhost:3000/api/proxy/app-xyz
// Append /api for your backend API routes
return `${config.STRONGLY_URL.replace(/\/$/, '')}/api`;
}
// Fallback for local development
return '/api';
}

const api = axios.create({
baseURL: getApiBaseUrl(),
timeout: 30000,
});

STRONGLY_SERVICES

JSON object containing all connected service credentials:

const services = JSON.parse(process.env.STRONGLY_SERVICES || '{}');

// Structure:
{
"services": {
"databases": {
"mongodb": [{
"id": "addon-xyz",
"type": "mongodb",
"connection": {
"connection_string": "mongodb://...",
"host": "addon-xyz.addons.svc.cluster.local",
"port": 27017
}
}]
},
"ai_gateway": {
"base_url": "http://localhost:3000/apps/app-xyz/ai-gateway",
"available_models": [...]
}
}
}

See STRONGLY_SERVICES Integration for detailed usage.

Authentication Headers

The platform injects authentication headers on all requests to your app:

HeaderDescriptionExample
X-Auth-User-IdUnique user identifierFsbHXu34LHShtmb9L
X-Auth-User-EmailUser's email addressuser@example.com
X-Auth-User-NameUser's display nameJohn Doe
X-Auth-App-RoleUser's role in this appadmin, developer, app
X-Auth-Platform-RolePlatform-wide roleadmin, user
X-Auth-AuthenticatedAuthentication statustrue or false

Using auth headers in Express:

// Middleware to extract user from headers
app.use((req, res, next) => {
req.user = {
id: req.headers['x-auth-user-id'] || 'anonymous',
email: req.headers['x-auth-user-email'] || null,
name: req.headers['x-auth-user-name'] || 'Anonymous',
appRole: req.headers['x-auth-app-role'] || 'app',
platformRole: req.headers['x-auth-platform-role'] || null,
authenticated: req.headers['x-auth-authenticated'] === 'true'
};
next();
});

// Use in routes
app.get('/api/profile', (req, res) => {
if (!req.user.authenticated) {
return res.status(401).json({ error: 'Not authenticated' });
}
res.json({ user: req.user });
});

Other Platform Variables

# Application metadata
APP_NAME=my-app
ENVIRONMENT=production # or development

# Kubernetes metadata
POD_NAME=my-app-7d8f6b9c4-x7k9m
POD_NAMESPACE=apps
POD_IP=10.0.2.15

Using .env Files

Include a .env file in your archive for additional variables:

.env:

# Development settings
DEBUG=true
CACHE_TTL=300

# Feature flags
FEATURE_NEW_UI=enabled
FEATURE_BETA_API=disabled
.env File Limitations
  • .env files are NOT encrypted
  • Don't put secrets in .env files
  • Use manifest secret: true for sensitive data
  • .env values override manifest defaults

Accessing Variables in Code

Node.js

// Access individual variables
const nodeEnv = process.env.NODE_ENV;
const apiKey = process.env.API_KEY;

// Parse STRONGLY_SERVICES
const services = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const mongoUrl = services.addons['addon-id-1'].connectionString;

Python

import os
import json

# Access individual variables
node_env = os.environ.get('NODE_ENV', 'development')
api_key = os.environ.get('API_KEY')

# Parse STRONGLY_SERVICES
services = json.loads(os.environ.get('STRONGLY_SERVICES', '{}'))
mongo_url = services['addons']['addon-id-1']['connectionString']

React (Build-time)

Variables prefixed with REACT_APP_ are embedded at build time:

// Access in React components
const apiUrl = process.env.REACT_APP_API_URL;
const version = process.env.REACT_APP_VERSION;

console.log('API URL:', apiUrl);
React Environment Variables

React environment variables must be prefixed with REACT_APP_ and marked as buildtime: true in the manifest.

Runtime Configuration Injection

For React/static apps, inject runtime configuration without rebuilding:

Manifest Configuration

type: react
static:
root: /app/build
config_file: /app/build/config.js
config_placeholder: __APP_CONFIG__

Template File

Create public/config.js with placeholder:

window.__APP_CONFIG__ = __APP_CONFIG__;

HTML Reference

Include in public/index.html:

<!DOCTYPE html>
<html>
<head>
<script src="%PUBLIC_URL%/config.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>

Access in React

const config = window.__APP_CONFIG__;

function App() {
const apiUrl = config.REACT_APP_API_URL;

return <div>API: {apiUrl}</div>;
}

At runtime, the platform replaces __APP_CONFIG__ with actual values:

window.__APP_CONFIG__ = {
"REACT_APP_API_URL": "https://api.acme.com",
"REACT_APP_VERSION": "1.0.0"
};

Updating Variables

During Deployment

  1. Navigate to Apps → Deploy App
  2. Configure environment variables in the form
  3. Provide values for required secrets
  4. Deploy application

After Deployment

  1. Navigate to app details page
  2. Click Configuration tab
  3. Update variable values
  4. Click Redeploy to apply changes
Redeploy Required

Environment variable changes require redeployment. The app will restart with new values.

Validation

The platform validates environment variables:

  • Required variables must have values
  • Secret variables are encrypted before storage
  • Build-time variables are passed to Docker build
  • Invalid names (spaces, special chars) are rejected

Best Practices

Naming Conventions

env:
# Good: Uppercase with underscores
- name: DATABASE_URL
- name: JWT_SECRET
- name: MAX_CONNECTIONS

# Bad: Lowercase or mixed case
- name: databaseUrl # Avoid
- name: jwtSecret # Avoid

Secret Management

env:
# Store as secret
- name: DB_PASSWORD
secret: true
required: true

# Store as regular variable
- name: DB_HOST
value: "postgres.example.com"
secret: false

Documentation

env:
- name: CACHE_TTL
value: "300"
description: Cache time-to-live in seconds

- name: MAX_RETRIES
value: "3"
description: Maximum number of retry attempts for failed requests

Environment-Specific Values

Use different values for Development vs Production:

# Development manifest
env:
- name: LOG_LEVEL
value: "debug"
- name: CACHE_ENABLED
value: "false"

# Production manifest
env:
- name: LOG_LEVEL
value: "error"
- name: CACHE_ENABLED
value: "true"

Troubleshooting

Variable Not Found

Problem: Application can't find environment variable

Solutions:

  • Check variable is defined in manifest
  • Verify variable name matches exactly (case-sensitive)
  • Ensure app was redeployed after adding variable
  • Check pod logs for startup errors

Secret Not Decrypted

Problem: Secret value appears as *** or is empty

Solutions:

  • Verify secret value was provided during deployment
  • Check secret is marked with secret: true in manifest
  • Redeploy application if secret was added later

Build-time Variable Not Available

Problem: Variable not available during Docker build

Solutions:

  • Ensure buildtime: true is set in manifest
  • Add ARG directive in Dockerfile
  • Check build logs for variable injection

Next Steps