Overview
Ecto has been developed since 2013, and its most active contributor on GitHub is josevalim. The docs split it into four parts: Ecto.Repo (where the data is), Ecto.Schema (what the data is), Ecto.Query (how to read it) and Ecto.Changeset (how to change it). Queries are written with Elixir macros, either keyword style (from w in Weather, where: ...) or piped (Weather |> where(city: "x") |> limit(10)), and are composable and parameterised.
There is no lazy loading or automatic change tracking: associations are preloaded explicitly and every insert or update passes through a changeset, which casts and validates input and records exactly what changes. This makes database access visible in code, at the cost of some extra typing compared with Active Record ORMs.
Most apps add ecto_sql, which provides SQL adapters (Postgrex for PostgreSQL, MyXQL for MySQL, Tds for SQL Server; ecto_sqlite3 for SQLite, and community adapters such as ClickHouse) and versioned migrations. Phoenix generators create Ecto schemas, migrations and contexts. Version 3.14 is current on HexDocs.
Pricing and plans
| Plan | Price | What you get |
|---|---|---|
| Ecto | $0 | Apache 2.0 licence |
What it does
- Repo
- Wraps the database connection and pool; all reads and writes go through it.
- Schemas
- Map tables (or any external data) to Elixir structs with typed fields and associations.
- Composable queries
- Keyword and pipe syntax built from macros, checked at compile time for syntax and safe from injection.
- Changesets
- Cast, validate and constrain changes before they reach the database, with errors ready for forms.
- Migrations (ecto_sql)
- Versioned migration modules with up/down or reversible change functions.
Strengths and limitations
Strengths
- Explicit data access with no hidden lazy loading
- Changesets give a clean, reusable validation layer
- Tight Phoenix integration and generators
- Very small open issue count; carefully maintained
Limitations
- Associations must be preloaded explicitly, which is more code than lazy-loading ORMs
- Elixir-only
- SQLite and ClickHouse adapters come from separate projects rather than ecto_sql itself
- Learning curve for developers used to Active Record-style ORMs
Who it suits
Good for
- Phoenix web applications
- Elixir services that need clear, validated writes
- Teams that value explicit database access
Look elsewhere if
- Non-Elixir stacks
- Developers who want lazy-loaded associations
Alternatives to Ecto
| Tool | From | Free option | Stages |
|---|---|---|---|
| Eloquent ORM Active Record ORM for Laravel | — | ||
| Active Record (Rails) Active Record ORM for Ruby on Rails | — | ||
| Bun (Go ORM) SQL-first Go ORM | — | ||
| Kysely Type-safe TypeScript SQL query builder | — | ||
| Prisma ORM Schema-first TypeScript ORM | $10/mo | Free tier | |
| SQLx Async Rust SQL toolkit | — |
Questions
Is Ecto an ORM?
It is a data mapping and query toolkit; it maps data to structs but has no lazy loading or implicit change tracking.
Which databases does Ecto support?
PostgreSQL, MySQL and SQL Server through ecto_sql adapters, SQLite through ecto_sqlite3, and others such as ClickHouse through community adapters.
How do migrations work in Ecto?
The ecto_sql package provides versioned migration modules run with mix ecto.migrate.
Sources read for this page