# How the TeslaMate Updater Module Checks for Software Updates

> Discover how the TeslaMate Updater module checks for software updates by querying the GitHub Releases API and comparing local and remote versions for seamless notifications.

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

---

**The TeslaMate Updater module queries the GitHub Releases API to compare the locally running version against the latest remote release, returning a structured update object that powers the in-app notification system.**

The TeslaMate Updater module provides automated version detection that keeps users informed about new releases without manual intervention. This Elixir-based system reads the current application version from the repository, fetches release metadata from GitHub, and surfaces upgrade notifications directly in the Settings interface. Understanding how the Updater module checks for software updates reveals a lightweight yet robust pattern for self-hosted application version management.

## Overview of the Update Detection Workflow

The update mechanism follows a deterministic pipeline designed to minimize external dependencies while providing reliable version comparison. When the Settings page loads, the system executes a series of operations to determine if the running instance is current.

The workflow involves:

- Reading the local version from the `VERSION` file at the repository root
- Issuing an HTTP GET request to the GitHub Releases API using the Tesla client
- Parsing the JSON payload to extract the latest tag and release assets
- Comparing semantic versions using Elixir's standard library
- Returning a populated struct indicating availability and download links
- Rendering conditional UI elements in the Phoenix LiveView interface

## Step-by-Step Implementation in lib/teslamate/updater.ex

All core logic resides in [`lib/teslamate/updater.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/updater.ex), where the module orchestrates external API communication and version arithmetic.

### Reading the Current Version from the VERSION File

The module determines the running version by reading a plain-text file committed to the repository root. This approach avoids compile-time version injection and allows runtime detection across different deployment methods.

```elixir
defp current_version do
  Path.join(:code.priv_dir(:teslamate), "../../VERSION")
  |> File.read!()
  |> String.trim()
end

```

The function constructs an absolute path to the `VERSION` file relative to the priv directory, ensuring compatibility with Mix releases and Docker containers.

### Querying the GitHub Releases API

The Updater module uses the Tesla HTTP client (wrapped by `TeslaMate.HTTP`) to fetch release metadata. The request targets the latest release endpoint with a standard User-Agent header.

```elixir
@github_release_api "https://api.github.com/repos/teslamate-org/teslamate/releases/latest"

def get_update do
  with {:ok, %Tesla.Env{status: 200, body: body}} <- Tesla.get(@github_release_api),
       {:ok, %{"tag_name" => tag, "assets" => assets}} <- Jason.decode(body) do
    # Version comparison logic...

  else
    _ -> %Update{available?: false}
  end
end

```

If the API returns a non-200 status or the JSON parsing fails, the function gracefully returns an update struct with `available?: false`, preventing UI errors during network outages.

### Parsing and Comparing Semantic Versions

After extracting the `tag_name` (e.g., `v1.27.0`) from the GitHub response, the module strips the leading "v" prefix and compares versions using `Version.compare/2`.

```elixir
latest_version = String.trim_leading(tag, "v")
current_version = current_version()

if Version.compare(latest_version, current_version) == :gt do
  %Update{
    available?: true,
    new_version: latest_version,
    release_url: "https://github.com/teslamate-org/teslamate/releases/tag/#{tag}",
    assets: assets
  }
else
  %Update{available?: false}
end

```

This comparison leverages Elixir's built-in semantic versioning support, correctly handling prerelease tags and build metadata according to the SemVer specification.

### Returning the Update Struct

The module encapsulates results in a `%TeslaMate.Updater.Update{}` struct with four fields:

- `available?` - boolean indicating if a newer version exists
- `new_version` - the semantic version string from GitHub (nil if current)
- `release_url` - direct link to the GitHub release page
- `assets` - list of downloadable artifacts including Docker images and binaries

When the local version matches or exceeds the remote release, the struct returns with `available?: false` and nullified metadata fields.

## Integrating Update Checks into the Web Interface

The Settings LiveView ([`lib/teslamate_web/live/settings_live/index.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/live/settings_live/index.ex)) consumes the Updater module to conditionally render upgrade banners. During the mount phase, the LiveView fetches update status and assigns it to the socket.

```elixir
def mount(_params, _session, socket) do
  {:ok,
   socket
   |> assign(:update, TeslaMate.Updater.get_update())}
end

```

The template then pattern-matches against the struct to display contextual messaging:

```elixir
<%= if @update.available? do %>
  <p>New version <%= @update.new_version %> is available!</p>
  <a href="<%= @update.release_url %>">View release</a>
<% else %>
  <p>You are running the latest version.</p>
<% end %>

```

This integration ensures users receive immediate visual feedback about available updates without leaving the application interface.

## Summary

- The **TeslaMate.Updater** module in [`lib/teslamate/updater.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/updater.ex) provides centralized version detection logic for the entire application.
- **Version detection** relies on reading the `VERSION` file at the repository root and comparing it against the GitHub Releases API using semantic versioning rules.
- **API communication** uses the Tesla HTTP client with graceful error handling that defaults to "no update available" when network requests fail.
- **Data encapsulation** occurs through the `%Update{}` struct, which carries availability status, version strings, release URLs, and asset metadata.
- **UI integration** happens in [`lib/teslamate_web/live/settings_live/index.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/live/settings_live/index.ex), where the LiveView assigns update data for conditional rendering in the Settings interface.

## Frequently Asked Questions

### How does TeslaMate determine the currently installed version?

TeslaMate reads the `VERSION` file located at the repository root using a private function in [`lib/teslamate/updater.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/updater.ex). The function constructs a path relative to the application priv directory, trims whitespace, and returns the semantic version string for comparison against GitHub releases.

### What happens if the GitHub API is unavailable when checking for updates?

The `get_update/0` function includes error handling in its `with` clause that catches HTTP failures or JSON parsing errors. When the API is unreachable, the function returns `%Update{available?: false}`, causing the Settings page to display the "latest version" message without crashing or hanging.

### Which HTTP client does TeslaMate use for update checks?

The Updater module uses the **Tesla** HTTP client, specifically wrapped by `TeslaMate.HTTP`, to execute GET requests against `https://api.github.com/repos/teslamate-org/teslamate/releases/latest`. The request includes proper User-Agent headers required by the GitHub API.

### Where does the Settings page display available updates?

The Settings LiveView in [`lib/teslamate_web/live/settings_live/index.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/live/settings_live/index.ex) calls `TeslaMate.Updater.get_update/0` during the mount phase and assigns the result to the socket. The corresponding template renders a conditional block that displays the new version number and release URL when `available?` is true.