# How the TeslaMate Release Module Manages Database Migrations

> Discover how the TeslaMate Release module expertly handles database migrations using Ecto. Learn about applying changes, executing rollbacks, and monitoring status for seamless updates.

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

---

**The `TeslaMate.Release` module serves as the central coordinator for all database migration activities in TeslaMate, leveraging Ecto to apply pending changes, execute rollbacks, and monitor migration status across every configured repository.**

The `teslamate-org/teslamate` repository relies on Ecto for database persistence, but delegates migration orchestration to a dedicated release module. Located at [`lib/teslamate/release.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/release.ex), this module provides idempotent, reliable functions that ensure the database schema remains synchronized with the application code during deployments and rollbacks.

## Core Migration Functions

The `TeslaMate.Release` module exposes a focused public API for managing database state. Each function wraps lower-level Ecto primitives to provide safe, repeatable operations.

### migrate/0

The `migrate/0` function applies **all pending migrations** for every Ecto repository defined in the application configuration. According to the source code in [`lib/teslamate/release.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/release.ex), it iterates over the list of repos returned by the private `repos/0` function and executes:

```elixir
Ecto.Migrator.with_repo(repo, fn repo ->
  Ecto.Migrator.run(repo, :up, all: true)
end)

```

This ensures that schema changes are applied transactionally across all configured databases before the application starts serving traffic.

### rollback/2

When reverting changes, the `rollback/2` function targets a **single repository** and rolls it back to a specific version. The function signature accepts a repository module and a timestamp version:

```elixir
def rollback(repo, version) do
  # Implementation filters repos list to target repo

  # Then executes:

  Ecto.Migrator.run(repo, :down, to: version)
end

```

This selective approach allows operators to revert specific databases without affecting others, using `Ecto.Migrator.run/3` with the `:down` direction and `to: version` option.

### seconds_since_last_migration/0

To support health checks and monitoring, the module provides `seconds_since_last_migration/0`, which returns the **age in seconds** of the most recent migration entry. The implementation queries the `schema_migrations` table directly:

```elixir
def seconds_since_last_migration do
  query =
    from(m in "schema_migrations",
      select: fragment("EXTRACT(EPOCH FROM (NOW() - inserted_at))")
    )

  Repo.one(query)
end

```

This raw SQL fragment calculates the epoch difference between the current time and the `inserted_at` timestamp of the latest migration record.

### repos/0 (Private)

The private `repos/0` function bootstraps the application environment to discover configured repositories. As implemented in [`lib/teslamate/release.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/release.ex), it ensures the `:ssl` application is started, loads the `:teslamate` application, and retrieves the `:ecto_repos` configuration:

```elixir
defp repos do
  Application.ensure_all_started(:ssl)
  Application.load(:teslamate)
  Application.fetch_env!(:teslamate, :ecto_repos)
end

```

This guarantees that migration commands operate on the complete set of repositories defined in [`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs) or environment-specific configuration files.

## Practical Usage Examples

During deployment, operators invoke these functions from IEx sessions or release scripts to ensure database consistency.

### Running All Pending Migrations

To apply all pending migrations across every configured repository:

```elixir
TeslaMate.Release.migrate()

```

This is typically executed from a Docker entrypoint script or distillery boot hook before the web server starts.

### Rolling Back to a Specific Version

If you need to revert the primary repository to a previous state:

```elixir
TeslaMate.Release.rollback(TeslaMate.Repo, 20210831153305)

```

Only the specified repository is affected; all other repos remain at their current versions.

### Checking Migration Status

For health monitoring or debugging, retrieve the time elapsed since the last migration:

```elixir
seconds = TeslaMate.Release.seconds_since_last_migration()
IO.puts("Last migration ran #{seconds} seconds ago")

```

## Key Source Files

Understanding the migration system requires familiarity with these components:

- **[`lib/teslamate/release.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/release.ex)** — Contains the core `TeslaMate.Release` module with `migrate/0`, `rollback/2`, and monitoring functions.
- **`priv/repo/migrations/`** — Directory containing individual migration files that define schema changes; these are executed by the release module.
- **[`config/config.exs`](https://github.com/teslamate-org/teslamate/blob/main/config/config.exs)** — Defines the `:ecto_repos` list that `TeslaMate.Release` reads to determine which repositories to manage.
- **[`mix.exs`](https://github.com/teslamate-org/teslamate/blob/main/mix.exs)** — Declares `ecto_sql` and related dependencies required for migration support.

## Summary

- The `TeslaMate.Release` module in [`lib/teslamate/release.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/release.ex) centralizes all database migration logic for the application.
- **migrate/0** applies pending changes across all configured Ecto repositories using `Ecto.Migrator.run/3` with `all: true`.
- **rollback/2** reverts a specific repository to a target version using the `:down` direction.
- **seconds_since_last_migration/0** queries the `schema_migrations` table directly to determine migration age.
- The module is invoked during deployment scripts to ensure schema consistency before application startup.

## Frequently Asked Questions

### How does TeslaMate apply migrations during deployment?

TeslaMate applies migrations by invoking `TeslaMate.Release.migrate/0` from the release script or container entrypoint. This function loads the application configuration, discovers all repositories via the private `repos/0` function, and executes `Ecto.Migrator.run/3` with the `:up` direction to apply pending changes.

### Can I roll back migrations for only one database?

Yes. The `rollback/2` function accepts a specific repository module (such as `TeslaMate.Repo`) and a version timestamp. It filters the configured repositories to match only the supplied module, then executes the rollback using `Ecto.Migrator.run/3` with `to: version`, leaving other repositories unaffected.

### How can I verify when the last migration was applied?

Use the `seconds_since_last_migration/0` function, which returns the number of seconds since the most recent entry in the `schema_migrations` table. This is useful for health checks that verify the database schema is current.

### Where does TeslaMate store migration files?

Migration files reside in `priv/repo/migrations/` within the repository. Each file contains an Ecto migration module defining specific schema changes, which `TeslaMate.Release` discovers and executes based on the version timestamps recorded in the database's `schema_migrations` table.