# How TeslaMate Manages Environment Configuration Across Dev, Test, and Production

> Discover how TeslaMate manages environment configuration across dev, test, and production. Learn about its three-layer system for seamless deployments and efficient development.

- Repository: [TeslaMate/teslamate](https://github.com/teslamate-org/teslamate)
- Tags: internals
- Published: 2026-06-23

---

**TeslaMate implements a three-layer environment configuration system using compile-time base settings in [`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs), environment-specific overrides in [`config/dev.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/dev.exs), [`config/test.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/test.exs), and [`config/prod.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/prod.exs), and runtime variable resolution in [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) that reads system environment variables at startup.**

TeslaMate, a self-hosted data logger for Tesla vehicles built on the Elixir/Phoenix framework, relies on a sophisticated environment configuration strategy to maintain distinct behaviors across development, testing, and production deployments. The system separates compile-time defaults from runtime secrets, allowing operators to deploy the same compiled release across different environments simply by adjusting environment variables. This approach ensures that database credentials, API keys, and host-specific settings remain external to the codebase while providing optimized settings for each stage of the development lifecycle.

## Configuration Architecture Overview

TeslaMate’s configuration follows a strict loading order that combines three distinct layers. First, the base configuration establishes common defaults for all environments. Second, environment-specific files override these defaults based on the `MIX_ENV` value. Third, the runtime configuration executes after the application starts, fetching final values from the system environment using `System.get_env/2` and `Util.fetch_env!/2` functions.

This layered approach means that settings in [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) take precedence over compile-time configurations in [`config/prod.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/prod.exs) or [`config/dev.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/dev.exs), enabling dynamic configuration without recompilation.

## Base Configuration Layer

The foundation of TeslaMate’s configuration resides in [`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs). This file defines settings shared across all environments, including the repository list, endpoint defaults, logger formatting, and gettext locale configuration.

Crucially, this file delegates to environment-specific configurations using the dynamic import statement:

```elixir
import_config "#{config_env()}.exs"

```

The `config_env/0` function returns the current environment atom (`:dev`, `:test`, or `:prod`), ensuring that the appropriate override file loads immediately after the base settings are established.

## Environment-Specific Overrides

Each deployment stage has a dedicated configuration file that tailors the application behavior for its specific context.

### Development Configuration ([`config/dev.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/dev.exs))

The development environment prioritizes developer experience and debugging capabilities. According to the TeslaMate source code, [`config/dev.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/dev.exs) enables **code reloading** for rapid iteration, configures detailed error pages with stack traces, and sets up live-reload patterns for the Phoenix endpoint. The HTTP server binds to port 4000, and the logger outputs debug-level information to assist with troubleshooting.

### Test Configuration ([`config/test.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/test.exs))

For the test environment, TeslaMate minimizes external dependencies and isolates database interactions. The [`config/test.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/test.exs) file explicitly **disables the HTTP server** to prevent port conflicts during parallel test runs. It configures the Ecto repository to use the **sandbox pool**, ensuring database transactions roll back after each test. Additionally, the logger level is set to `:warning` to reduce noise during test execution.

### Production Configuration ([`config/prod.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/prod.exs))

Production settings in [`config/prod.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/prod.exs) focus on performance and security. The configuration forces the web server to start with `server: true`, points to a pre-compiled static asset manifest for efficient file serving, and configures a minimal logger suitable for containerized deployments. Unlike development, code reloading is strictly disabled, and error pages present user-friendly messages without revealing implementation details.

## Runtime Configuration Layer

Executed after compilation, [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) resolves final configuration values from environment variables. This file is critical for containerized deployments, allowing operators to inject secrets and host-specific settings without rebuilding the application.

### Database Connection Settings

TeslaMate constructs database connections from individual environment variables rather than a single connection string. As implemented in lines 89-122 of [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs), the system reads:

- `DATABASE_USER`, `DATABASE_PASS`, `DATABASE_HOST`, `DATABASE_NAME`, `DATABASE_PORT` for basic connectivity
- `DATABASE_POOL_SIZE` and `DATABASE_TIMEOUT` for connection management
- Optional SSL settings for encrypted database connections

These variables include sensible defaults for local development but require explicit values in production.

### HTTP Binding and Endpoint Security

The HTTP server configuration utilizes `Util.choose_http_binding_address/0` to parse `HTTP_BINDING_ADDRESS` and `PORT` environment variables (lines 52-86). This utility function determines whether to bind to a specific IP address, a Unix socket, or the default IPv6 socket.

Security-sensitive endpoint settings are configured in lines 55-66, reading `VIRTUAL_HOST`, `URL_PATH`, `SECRET_KEY_BASE`, and `SIGNING_SALT` from the environment. When these are not provided, the system falls back to cryptographically secure random strings generated at runtime.

### MQTT and Auxiliary Services

When `DISABLE_MQTT` is not set to `"true"` (and outside of test environments), TeslaMate initializes the MQTT client using environment variables for host, port, credentials, TLS flags, and namespace (lines 68-78).

Additional optional configurations include `IMPORT_DIR` for bulk data imports and `SRTM_CACHE` for elevation data caching (lines 80-88).

## Practical Configuration Examples

### Running TeslaMate in Development

To start the application locally with hot reloading and debug output:

```bash
export DATABASE_USER=postgres
export DATABASE_PASS=postgres
export DATABASE_HOST=localhost
export SECRET_KEY_BASE=$(openssl rand -base64 48)
mix deps.get
mix ecto.setup
MIX_ENV=dev mix phx.server

```

### Executing the Test Suite

The test environment loads automatically when `MIX_ENV` is set to `test`:

```bash
MIX_ENV=test mix test

```

This configuration uses the sandbox database pool and suppresses the HTTP server to ensure isolated, fast test execution.

### Deploying Production Containers

For Docker deployments, pass configuration via environment variables:

```bash
docker run -e DATABASE_URL=postgres://user:pass@db/teslamate \
           -e SECRET_KEY_BASE=$(openssl rand -base64 48) \
           -e VIRTUAL_HOST=teslamate.example.com \
           -e PORT=4000 \
           -e MQTT_HOST=mqtt.example.com \
           -e MQTT_NAMESPACE=teslamate \
           -p 4000:4000 \
           teslamate/teslamate:latest

```

## Summary

- **Three-layer architecture**: TeslaMate combines base settings ([`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs)), environment overrides (`config/{dev,test,prod}.exs`), and runtime resolution ([`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs)).
- **Compile-time vs. runtime**: Values in [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) override compile-time settings, enabling dynamic configuration without recompilation.
- **Development features**: Code reloading, detailed errors, and debug logging optimize the local development experience.
- **Test isolation**: The test environment disables the HTTP server and uses Ecto sandbox mode for database transaction rollback.
- **Production hardening**: Pre-compiled assets, minimal logging, and mandatory environment variables for secrets ensure secure deployments.
- **Database flexibility**: Individual connection parameters (`DATABASE_HOST`, `DATABASE_PORT`, etc.) are read at runtime with sensible development defaults.

## Frequently Asked Questions

### How do I switch between development and production configurations in TeslaMate?

Set the `MIX_ENV` environment variable to `dev`, `test`, or `prod` before starting the application. This variable determines which environment-specific file ([`config/dev.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/dev.exs), [`config/test.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/test.exs), or [`config/prod.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/prod.exs)) gets loaded after the base configuration. For production Docker deployments, the image typically defaults to `MIX_ENV=prod`, while local development uses `MIX_ENV=dev`.

### Can I change database settings without recompiling the TeslaMate release?

Yes. Because [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) executes at application startup using `System.get_env/2`, you can modify `DATABASE_USER`, `DATABASE_PASS`, `DATABASE_HOST`, and other connection variables without rebuilding the release. Simply restart the container or process with the new environment variables, and the runtime configuration will pick up the changes immediately.

### What is the difference between compile-time and runtime configuration in TeslaMate?

Compile-time configuration, found in [`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs) and the environment-specific files, is evaluated when the application is built and baked into the release. Runtime configuration, defined in [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs), executes when the application starts, reading values from the system environment. This separation allows sensitive data like `SECRET_KEY_BASE` to remain outside the compiled artifact while ensuring deployment-specific settings can be adjusted post-build.

### How does TeslaMate handle sensitive secrets like SECRET_KEY_BASE?

The application expects `SECRET_KEY_BASE` and `SIGNING_SALT` as environment variables read by [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs) (lines 55-66). If these are not provided, TeslaMate generates cryptographically secure random strings at runtime. However, for production stability—especially in clustered deployments—you should explicitly set these variables to ensure session continuity across restarts and nodes.