How Dependencies Are Configured in the TeslaMate Supervisor Tree

TeslaMate configures its runtime process hierarchy through a single OTP supervisor in lib/teslamate/application.ex that uses the :one_for_one restart strategy, dynamically assembling child specifications based on environment settings for MQTT and import directories.

TeslaMate, the open-source self-hosted data logger for Tesla vehicles, relies on a robust Erlang/OTP supervision tree to manage its concurrent processes. The foundation of this architecture lies in how dependencies are configured in the TeslaMate supervisor tree, specifically within the application startup sequence. By leveraging Elixir's Supervisor behaviour, TeslaMate ensures that critical components like database connections, API clients, and background workers restart independently when failures occur.

The Root Supervisor Architecture

The entry point for the supervision tree is TeslaMate.Application.start/2, defined in lib/teslamate/application.ex. This function initializes the entire runtime by starting a supervisor with the :one_for_one strategy:


# lib/teslamate/application.ex

def start(_type, _args) do
  # …

  Supervisor.start_link(children(), strategy: :one_for_one, name: TeslaMate.Supervisor)
end

The :one_for_one strategy ensures that if a single child process crashes, only that specific process is restarted, leaving the rest of the system unaffected. This design provides fault isolation between distinct functional areas like database access and vehicle communication.

Dynamic Child Specification in children/0

The children/0 function serves as the dependency manifest, returning a list of child specifications that varies based on runtime configuration. The function checks two environment keys:

  • Application.get_env(:teslamate, :import_directory) – Determines if the system should run in import mode
  • Application.get_env(:teslamate, :mqtt) – Controls whether the MQTT bridge starts

Each entry in the returned list follows Elixir's child specification format, either as a module name (for simple start_link functions) or as a tuple {module, opts} for processes requiring specific initialization arguments.

Normal Mode Configuration

When operating in standard mode (no import directory configured), children/0 returns the following list:

[
  TeslaMate.Repo,
  TeslaMate.Vault,
  TeslaMate.HTTP,
  TeslaMate.Api,
  TeslaMate.Updater,
  {Phoenix.PubSub, name: TeslaMate.PubSub},
  TeslaMateWeb.Endpoint,
  TeslaMate.Terrain,
  TeslaMate.Vehicles,
  if(mqtt_config != nil, do: {TeslaMate.Mqtt, mqtt_config}),
  TeslaMate.Repair
]
|> Enum.reject(&is_nil/1)

The Enum.reject(&is_nil/1) filter at the end removes the optional MQTT child when the configuration is absent, ensuring the supervisor only starts configured dependencies.

The responsibilities of these core processes include:

  • TeslaMate.Repo – Manages the Ecto database connection pool
  • TeslaMate.Vault – Handles encrypted storage of API tokens using Cloak
  • TeslaMate.HTTP – Provides a thin wrapper around the Tesla HTTP client for outbound requests
  • TeslaMate.Api – Implements the high-level Tesla API client for vehicle communication
  • TeslaMate.Updater – Manages firmware update tracking and data migrations
  • Phoenix.PubSub – Enables the Pub/Sub backbone for LiveView real-time updates
  • TeslaMateWeb.Endpoint – Starts the Phoenix HTTP server
  • TeslaMate.Terrain – Provides SRTM elevation data lookups
  • TeslaMate.Vehicles – Supervises individual vehicle process instances
  • TeslaMate.Repair – Runs background repair and maintenance tasks

Import Mode Configuration

When Application.get_env(:teslamate, :import_directory) returns a path, the supervision tree switches to import mode with a modified dependency list:

[
  TeslaMate.Repo,
  TeslaMate.Vault,
  TeslaMate.HTTP,
  TeslaMate.Api,
  TeslaMate.Updater,
  {Phoenix.PubSub, name: TeslaMate.PubSub},
  TeslaMateWeb.Endpoint,
  {TeslaMate.Terrain, disabled: true},
  {TeslaMate.Repair, limit: 250},
  {TeslaMate.Import, directory: import_directory}
]

Key differences from normal mode include:

  • TeslaMate.Terrain starts with disabled: true to skip elevation lookups during bulk imports
  • TeslaMate.Repair receives a limit: 250 option to throttle background work
  • TeslaMate.Import is added to process CSV files from the specified directory

Optional MQTT Integration

The MQTT dependency demonstrates conditional supervision. Rather than using a static list, the configuration evaluates at runtime:

if(mqtt_config != nil, do: {TeslaMate.Mqtt, mqtt_config})

When the :mqtt key exists in the application environment, the tuple {TeslaMate.Mqtt, mqtt_config} enters the children list. Otherwise, the expression returns nil, and Enum.reject(&is_nil/1) filters it out before the supervisor starts. This pattern allows the same codebase to support both MQTT-enabled and MQTT-disabled deployments without code changes.

Extending the Supervision Tree

To add a new dependency, such as a telemetry collector, you must modify the children/0 function in lib/teslamate/application.ex. For example, adding a TeslaMate.Telemetry GenServer:


# Inside lib/teslamate/application.ex → children/0

[
  # … existing children …

  TeslaMate.Vehicles,
  TeslaMate.Telemetry,      # ← new child

  if(mqtt_config != nil, do: {TeslaMate.Mqtt, mqtt_config}),
  TeslaMate.Repair
]
|> Enum.reject(&is_nil/1)

Because the supervisor uses :one_for_one, the new telemetry process starts automatically during application boot and restarts independently if it crashes.

Summary

  • TeslaMate uses a single supervisor in lib/teslamate/application.ex with the :one_for_one restart strategy to manage all runtime dependencies.
  • The children/0 function dynamically builds the child specification list based on environment variables :import_directory and :mqtt.
  • Normal mode starts eleven core processes including database connections, API clients, and background workers.
  • Import mode modifies the tree to disable terrain lookups, throttle repairs, and add the CSV import processor.
  • Optional dependencies use runtime conditionals with Enum.reject(&is_nil/1) to filter unconfigured processes.
  • Configuration originates in config/config.exs and environment-specific files (dev, prod, test).

Frequently Asked Questions

What restart strategy does TeslaMate use for its supervisor tree?

TeslaMate uses the :one_for_one strategy, implemented in lib/teslamate/application.ex. This means if a single child process fails, the supervisor restarts only that specific process while leaving all other sibling processes running. This provides fault isolation between the database pool, API clients, and web interface.

How do I disable the MQTT dependency in TeslaMate?

Remove the :mqtt configuration from your config/config.exs or environment-specific config file. When Application.get_env(:teslamate, :mqtt) returns nil, the children/0 function in lib/teslamate/application.ex passes nil to the MQTT slot, and Enum.reject(&is_nil/1) filters it out before the supervisor starts. No code changes are required.

What happens when an import directory is configured in TeslaMate?

When the :import_directory environment variable is set, TeslaMate switches to import mode. The children/0 function returns a modified list that starts TeslaMate.Terrain with disabled: true, limits TeslaMate.Repair to 250 concurrent tasks, and adds TeslaMate.Import to process CSV files from the specified directory. This optimizes the supervision tree for bulk data ingestion rather than real-time vehicle monitoring.

Where does TeslaMate read its supervision configuration from?

TeslaMate reads configuration from the application environment, specifically the Application.get_env/2 calls in lib/teslamate/application.ex. The relevant keys (:mqtt and :import_directory) are defined in config/config.exs and can be overridden in environment-specific files like config/prod.exs or config/dev.exs. The supervisor tree builds dynamically at runtime based on these values.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →