Skip to content

Environment Variables

This document describes how to configure environment variables for working with OWOX Data Marts. The system automatically loads configuration when starting the application with the owox serve command.

OWOX Data Marts can receive environment variables in two ways:

  • From system environment - variables set directly in the runtime environment
  • From configuration file - variables loaded from a .env file

Depending on the selected database type for the backend (DB_TYPE) and identity provider (IDP_PROVIDER), you need to set the corresponding additional environment variables:

  • For DB_TYPE=mysql - add MySQL connection variables (DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE)
  • For IDP_PROVIDER=better-auth - add Better Auth variables (IDP_BETTER_AUTH_SECRET, IDP_BETTER_AUTH_BASE_URL, etc.)

The complete list of all available environment variables is located in the .env.example file in the project root directory.

You can configure environment variables using one of the following methods:

By default, the owox serve command looks for a .env file in the current directory (where you run the command).

Create and edit the .env file and set the values required for your configuration:

Terminal window
# Common variables
PORT=3030
LOG_FORMAT=pretty
# Database
DB_TYPE=sqlite
SQLITE_DB_PATH=./database/backend.db
# Identity provider
IDP_PROVIDER=none

Various ways to specify the path to the file:

Terminal window
# 1. If .env is in the current directory
owox serve
# 2. If .env is in another location - via flag
owox serve --env-file /path/to/.env
owox serve -e /path/to/.env

When using containers, environment variables are passed from outside the container inside through the corresponding platform mechanisms (Docker, Kubernetes, etc.).

🐳 Containers: Environment variables are set outside the container and passed inside during startup. Inside the container, the application sees them as regular environment variables.

Most hosting platforms provide their own interface for setting environment variables. Usually it’s an “Environment Variables” or “Config Vars” section in project settings.

Some environment variables can be configured directly through command line arguments. This option provides the highest priority for configuration:

Terminal window
# Using command line arguments (highest priority)
owox serve --port 3030 --log-format json
# Combined with environment file
owox serve --env-file .env.production --port 3030

⚠️ Limited scope: Only a limited set of variables can be configured through command line arguments. Currently supported: PORT (via --port) and LOG_FORMAT (via --log-format). For other variables, use environment files or system environment variables.

Set environment variables directly before running the command:

Terminal window
# Linux/macOS/Windows (Git Bash)
DB_TYPE=sqlite SQLITE_DB_PATH=./database/backend.db IDP_PROVIDER=none owox serve
# Windows (Command Prompt)
set DB_TYPE=sqlite && set SQLITE_DB_PATH=./database/backend.db && set IDP_PROVIDER=none && owox serve
# Windows (PowerShell)
$env:DB_TYPE="sqlite"
$env:SQLITE_DB_PATH="./database/backend.db"
$env:IDP_PROVIDER="none"
owox serve

This section describes the internal logic of the environment variable loading system. Understanding this order will help you configure the correct setup and diagnose problems.

The system loads environment variables in the following priority order (highest to lowest):

1. Command Line Arguments (Highest Priority)

Section titled “1. Command Line Arguments (Highest Priority)”

Variables specified through command line arguments override all other sources:

Terminal window
owox serve --port 3030 --log-format json

⚠️ Note: Only --port and --log-format are currently supported as command line arguments.

Variables set directly in the runtime environment (system environment variables or variables set through hosting platform interfaces).

When you specify a path to a configuration file via --env-file:

Terminal window
owox serve --env-file /path/to/.env.production

If no environment file is explicitly specified, the system looks for a .env file in the current directory:

Terminal window
owox serve

If variables are not set through any of the above methods, the system uses default values:

PORT=3000
LOG_FORMAT=pretty

Example demonstrating priority:

Terminal window
# All these sources can provide PORT value:
# 1. Command line argument (highest priority): --port 3030
# 2. System environment: export PORT=3010
# 3. Explicitly specified file: PORT=3020 in custom.env
# 4. Default .env file: PORT=3000
# 5. Default value: PORT=3000 (lowest priority)
owox serve --env-file custom.env --port 3030
# Result: PORT=3030 (from command line argument)
  • PUBLIC_ORIGIN: Base public URL of the application (scheme + host [+ optional port]).

    • Examples: http://localhost:3000, https://data-marts.example.com
    • Default: http://localhost:${PORT}
    • In production, set this to your actual deployment URL.
  • LOOKER_STUDIO_DESTINATION_ORIGIN: Public origin used to generate the deployment URL for the Data Studio Destination.

    • If empty, it falls back to PUBLIC_ORIGIN.
    • Example: https://looker.example.com
  • MCP_DYNAMIC_CLIENT_ALLOWED_REDIRECT_ORIGINS: Comma-separated HTTPS origins allowed as OAuth redirect targets for dynamic MCP clients.

    • Loopback HTTP redirects for desktop/CLI clients are always allowed.
    • Example for Claude web: https://claude.ai
    • Default: empty.
  • MCP_PUBLIC_BASE_URL: Public origin of the shared hosted MCP server.

    • Example: https://mcp.owox.com
    • MCP_OAUTH_RESOURCE defaults to ${MCP_PUBLIC_BASE_URL}/mcp when not set.
    • Project-specific MCP URLs are derived from this value. For MCP_PUBLIC_BASE_URL=https://mcp.owox.com, the project URL format is https://{projectId}.mcp.owox.com/mcp.
    • Do not configure a separate project-domain environment variable. The deployment must route both mcp.owox.com and *.mcp.owox.com to the same MCP backend and preserve Host, X-Forwarded-Host, and X-Forwarded-Proto.
  • CORS_ALLOWED_HEADERS: Additional comma-separated request headers allowed by the API CORS configuration.
    • The values are added to the default allowed headers: content-type, authorization, x-owox-authorization.
    • Example for local tunnels or proxies: CORS_ALLOWED_HEADERS=ngrok-skip-browser-warning,x-custom-header

DB_MYSQL_SSL, IDP_BETTER_AUTH_MYSQL_SSL, IDP_OWOX_MYSQL_SSL enable TLS for MySQL (mysql2). Supported formats:

  • Boolean-like (strings)

    • true{} (enable TLS with default options: rejectUnauthorized: true)
    • false or empty → no ssl field (TLS disabled)
  • JSON object (forwarded to mysql2 TLS options)

    • Strict CA verification:
      • {"rejectUnauthorized": true}
    • Custom CA bundle (inline PEM):
      • {"rejectUnauthorized": true, "ca": "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"}
    • Mutual TLS (client cert + key):
      • {"rejectUnauthorized": true, "cert": "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n", "key": "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"}
    • Minimum TLS version (TLS 1.2):
      • {"minVersion": "TLSv1.2", "rejectUnauthorized": true}

See also: mysql2 official SSL documentation — https://sidorares.github.io/node-mysql2/docs/documentation/ssl

Plugins are third-party web apps embedded in a sandboxed iframe. These variables control who may publish them and how OWOX Data Marts reads their GitHub sources.

VariablePurpose
OWOX_DEPLOYMENT_PLUGIN_PUBLISHER_API_KEY_IDSComma-separated API key IDs allowed to publish, suspend and resume plugins for the whole deployment.
GITHUB_TOKENRead-only, fine-grained PAT for reading private plugin repositories. Self-managed deployments.
GITHUB_APP_ID, GITHUB_APP_SLUG, GITHUB_APP_PRIVATE_KEYOWOX Data Marts GitHub App credentials, for reading private repositories in the cloud. Required together. The key takes the whole PEM with newlines as \n, or just its base64 body with the BEGIN/END lines stripped when a secret store mangles the armour.
GITHUB_API_BASE_URLGitHub REST base URL. Override only for GitHub Enterprise.
PLUGIN_HOST_SYNC_MIN_INTERVAL_SECOptional minimum seconds between two synchronizations of the same plugin. Defaults to 30 with GitHub App or server-token access and 300 with anonymous access. An explicit value overrides every access mode. During the cooldown, publishing reuses the last validated version.
PLUGIN_HOST_REMOTE_PROBE_TIMEOUT_MSTimeout for probing a plugin’s delivery URL. Default 8000.

Plugin JSON collections use a named database connection. With no additional variables it falls back option-by-option to the main DB_* configuration (and to SQLITE_DB_PATH for SQLite), which is the recommended local and self-hosted setup. A Cloud deployment can isolate this data in a separate MySQL instance by setting the variables below.

VariableFallback
PLUGIN_COLLECTIONS_DB_TYPEDB_TYPE
PLUGIN_COLLECTIONS_SQLITE_DB_PATHSQLITE_DB_PATH / default app path
PLUGIN_COLLECTIONS_DB_HOSTDB_HOST
PLUGIN_COLLECTIONS_DB_PORTDB_PORT
PLUGIN_COLLECTIONS_DB_USERNAMEDB_USERNAME
PLUGIN_COLLECTIONS_DB_PASSWORDDB_PASSWORD
PLUGIN_COLLECTIONS_DB_DATABASEDB_DATABASE
PLUGIN_COLLECTIONS_DB_MYSQL_SSLDB_MYSQL_SSL

Blank override values count as absent. The collection connection has its own migration table, and RUN_MIGRATIONS applies pending migrations to both databases. Migration status also checks both by default. A down migration targets only the main database by default; set MIGRATIONS_DATA_SOURCE=pluginCollections when intentionally reverting the latest collection migration. MIGRATIONS_DATA_SOURCE=all is rejected for down migrations because the two histories advance independently.

The publisher allowlist is the authorization model for deployment-scope publishing — it stands in for an administration panel that is deliberately not built. An unset or blank value denies everyone; it never means “any key”. A Project Admin without an allowlisted key can still publish to their own project, and any member can publish for themselves.

A vendor may name your origin in a Content-Security-Policy: frame-ancestors directive instead of allowing * or https:. The origin compared against is PUBLIC_ORIGIN, the same value the rest of the deployment uses — the page that embeds a plugin is served from it, so a plugin-specific copy could only drift away from the real one.

GitHub access falls back in order: App installation token, then GITHUB_TOKEN, then anonymous. Public repositories need no credential at all, and an App configured but not installed on a given public repository does not block it.

See the plugin authoring guide for what this means on the plugin side.

The system outputs detailed messages about the loading process to help you understand what’s happening during environment setup:

Terminal window
owox serve --env-file .env.production

Expected success messages:

  • 📂 Using specified environment file: .env.production
  • 🔄 Starting to process environment file: .env.production
  • ✅ Set 5 variables
  • ✨ Environment file processed successfully

Expected file path resolution messages:

  • 📂 Using specified environment file: /path/to/.env.production (when --env-file is specified)
  • ⚙️ Using default environment file: /current/directory/.env (default fallback)

Expected file processing messages:

  • 🔄 Starting to process environment file: .env.production
  • ✅ Set 5 variables
  • ⏭️ Skipped 2 existing variables: PORT (already exists), LOG_FORMAT (already exists)
  • 🗑️ Ignored 1 invalid variables: EMPTY_VAR (empty string value)
  • ✨ Environment file processed successfully
🔍 Environment file not found: /path/to/.env.production

Solution: Check the correctness of the file path and ensure the file exists.

📖 Failed to read file /path/to/.env: ENOENT: no such file or directory

Solution: Verify file permissions and path accessibility.

💥 Empty content or failed to parse environment file: /path/to/.env

Solution: Check the syntax of the .env file and ensure it’s not empty. The file should contain valid KEY=value pairs.

🔍 Environment file not found: /current/directory/.env
🚫 Failed to process environment file

Solution:

  1. Create a .env file in the root directory
  2. Specify the correct path via --env-file
  3. Set variables directly in the environment (without using a file):
    • Via environment variables: PORT=3030 DB_TYPE=sqlite owox serve
    • Via hosting platform environment variables interface
    • Via system environment variables

When variables are ignored or skipped, the system provides specific reasons:

  • EMPTY_VAR (empty string value) - Variable has no value after trimming
  • INVALID_KEY (invalid key) - Key is empty or contains only whitespace
  • UNDEFINED_VAR (undefined/null value) - Variable is undefined or null
  • PORT (already exists) - Variable already exists and override is disabled