Ecto SQL sits between Ecto and your database, and owns the parts that hurt
SQL-based adapters for Ecto and database migrations
At a glance
- What is it?
- ecto_sql provides the SQL adapter layer for Ecto, with default implementations for Postgres, MySQL and MSSQL, a transaction based test sandbox, and migrations delivered through Mix tasks. It is worth adopting if you already use Ecto, and only worth adopting then.
- Who is it for?
- Use ecto_sql when your application already runs on Ecto and you want a relational adapter with a test sandbox and migrations that come out of the same package. Do not reach for it as a standalone SQL toolkit, because the pieces only make sense as part of Ecto.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An adapter layer, not a database driver
ecto_sql is the piece that turns Ecto's query abstraction into real SQL. The README describes it as building blocks for writing SQL adapters for Ecto, which is a narrower and stranger promise than it first sounds. It is not a driver, it is not an ORM, and it does not query a database on its own. It is the layer that knows how Ecto's schemas, changes and queries should be expressed in SQL for a particular engine.
The audience is therefore narrow and self-selecting. If you are writing an Elixir application with Ecto as its data layer and you want a relational backend, this package is where the Postgres, MySQL or MSSQL specifics live. If you want an Elixir SQL library with no Ecto dependency, this is the wrong package, because the README points new users to the Ecto repository for how to get started rather than describing an independent setup.
The primary language is Elixir, the licence is Apache-2.0, and the top level of the repository shows a normal Hex library: mix.exs and mix.lock for the package definition, lib/ for the source, test/ for unit tests, integration_test/ for the database specific suites, guides/ for documentation, bench/ for benchmarks, an Earthfile for containerised runs, and CHANGELOG.md for release notes. The mix.lock file is worth noting early, since it is where the exact dependency versions are pinned.
Ecto.Adapters.SQL is the one module every adapter passes through
The README lists the entry point as the Ecto.Adapters.SQL module, described as the entry point for all SQL based adapters. That single choke point is the architecture of this package. Adapters for different engines share the common behaviour and differ in the details of dialect, connection handling and driver choice.
Three default implementations ship in the box. Ecto.Adapters.Postgres covers Postgres, Ecto.Adapters.MyXQL covers MySQL, and Ecto.Adapters.Tds covers MSSQL. The names of the first two tell you what the driver layer is underneath, MyXQL being a MySQL client and Tds being the SQL Server client, so the project is a thin translation layer over existing client libraries rather than something that speaks the wire protocol itself.
Because Postgres, MySQL and MSSQL are all represented, the shared code has to deal with three different dialects, three different type systems and three different sets of surprises. That is the trade-off of a single common entry point: an application can move between engines through configuration, but each engine specific quirk still leaks somewhere, and the repository layout shows that integration_test/ exists precisely to test those quirks per database. The README names those three suites as pg, myxql and tds, one per built-in adapter.
The test sandbox runs concurrent tests inside transactions
Ecto.Adapters.SQL.Sandbox is the feature most teams adopt the package for. The README describes it as a test sandbox that concurrently runs database tests inside transactions. The mechanism is what makes it interesting: each test borrows a connection, work happens inside a transaction, and the transaction is rolled back afterwards, so tests start from a clean state without the slow, brittle dance of truncating tables between cases.
The word concurrently is the part that matters. A sandbox that could only serialise tests would slow a suite down badly, and the fact that the sandbox is described as concurrent means the implementation can hand out separate checked out connections while each one keeps its own transaction. This is the part of the design that a homegrown test helper usually cannot reproduce without a lot of work.
The limitation is that the sandbox lives in ecto_sql rather than in Ecto itself, and it depends on a real database server. A test suite built on the sandbox needs a running Postgres, MySQL or MSSQL instance, not an in-process substitute. That is a reasonable requirement for integration level confidence and a real cost for teams who want fast unit tests with no infrastructure dependency at all.
Migrations arrive as Mix tasks rather than a separate tool
The fourth feature listed is support for database migrations via Mix tasks. In Elixir that means migrations live in the same toolchain as the rest of the build, so schema changes are run with the same mix command that compiles and tests the project, and they are versioned in the same repository as the code that depends on them.
For an adopter this removes a category of work. You do not pick a separate migration tool and then wire it to the ORM, because the migration story is part of the adapter package already. It also means the migration behaviour is tied to the adapter version, which has a downside: the CHANGELOG.md file in the repository is where changes to migration behaviour would show up, and there is no versioning scheme for migrations documented in the README, such as a numbered or timestamped naming convention.
A related gap is worth naming explicitly. The README says nothing about down migrations, rollback of a release that already ran, or what happens when a migration fails halfway. If your deployment practice depends on reversible schema changes, you need to look at the actual migration code in lib/ rather than trusting that the feature list covers it. The feature list is a list of what exists, not a description of the guarantees.
Cloning the repository and pointing the suite at one adapter
The README describes how to work on ecto_sql itself rather than how to install it into an application, and the setup is a clone followed by a dependency fetch. That is the first real use for a developer who wants to read or modify the source.
$ git clone https://github.com/elixir-ecto/ecto_sql.git
$ cd ecto_sql
$ mix deps.get
$ mix testExpect the unit tests to run without a database, since the README separates the unit suite from the integration suites. The clone step needs the GitHub URL, deps.get resolves the packages listed in mix.exs using the versions pinned in mix.lock, and mix test runs the suite in test/.
Selecting an engine is a matter of setting an environment variable before the same command. The README documents the ECTO_ADAPTER variable, and pg, myxql and tds are the values that map to the three built-in adapters.
$ ECTO_ADAPTER=pg mix testThat single variable is the whole selection mechanism, which is convenient for CI and confusing for newcomers. There is no documented configuration file for choosing an adapter in a consuming application, because that choice belongs to Ecto and the repo it belongs to.
MSSQL integration testing expects a Docker container on port 1433
Running the integration suites requires the database to be available locally. The README is direct about this: PostgreSQL and MySQL can be installed directly on most systems, but for MSSQL you may need to run it as a Docker image. The image command publishes the SQL Server port on the host and sets the two environment variables the server image requires.
docker run -d -p 1433:1433 --name mssql -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=some!Password' mcr.microsoft.com/mssql/server:2017-latestThe port mapping 1433:1433 and the container name mssql are the two things you need to keep if you script this. The password in the README is an example, and it is a literal example that would be a poor choice outside a laptop.
This is where the package's testing story stops being self-contained. The unit suite is comfortable, but the integration suites assume either local server software or a container runtime, and on CI the difference between the three engines turns into different setup steps per database. The integration_test/ directory in the repository is where that per-database divergence lives, and the README advises running the relevant suite when you change logic specific to a database.
Earthly runs everything, and its pinned base image arguments look dated
There is a third testing path: running the integration tests in a containerised environment with earthly, which also needs Docker installed. The Earthfile at the top of the repository is the definition those targets come from, and the simplest invocation runs the whole set.
$ earthly -P +allThe interactive form is the more interesting one, because it drops you into a container shell for a given target so you can inspect the database directly, and the targets are per engine: integration-test-mysql, integration-test-mssql and integration-test-postgres.
$ earthly -P -i --build-arg ELIXIR_BASE=1.8.2-erlang-20.3.8.26-alpine-3.11.6 --build-arg MYSQL=5.7 +integration-test-mysqlLook closely at those build arguments. ELIXIR_BASE points at Elixir 1.8.2 with Erlang 20.3.8.26 on Alpine 3.11.6, MYSQL at 5.7, POSTGRES at 11.11. Those are the versions a reader would copy, and they are far behind the versions a current project would want to test. The README gives no explanation and no note about updating them, and the repository has no GitHub releases to cross-reference. Treat the documented build args as a starting point to edit rather than as a recommended matrix.
The payoff of the interactive shell is direct access to the databases, which the README lists as separate client commands for Postgres, MySQL and sqlcmd.
Apache-2.0 licensing and a project versioned through Hex rather than tags
The licence is Apache License 2.0, with the full text in LICENSE.md and the copyright history naming Plataformatec from 2012 and Dashbit from 2020. Apache-2.0 is permissive and its obligations are similar for internal and distributed use, so for most Elixir teams the licensing question is settled quickly. The clause worth reading yourself is the patent grant in that licence, which is one of the reasons it is widely chosen over GPL-style terms for libraries.
The maintenance picture comes from the repository facts rather than from release tags. The repository is not archived and the last push was on 2026-10-17, which puts active work on the master branch at that date. At the same time the repository has no GitHub releases at all. That combination is normal for a Hex library, where versions are cut from mix.exs and published to hex.pm, but it has a consequence: there is no tag list to browse, so CHANGELOG.md is the release history you have.
For upgrade planning, that means reading CHANGELOG.md between your pinned version in mix.lock and the version you intend to move to, and watching the adapter behaviour changes in it rather than scanning release notes. The README also names mix test.all as the target that runs unit tests together with all integration suites, which is the command to run before trusting a version bump across three database engines.
Editorial conclusion
Use ecto_sql when your application already runs on Ecto and you want a relational adapter with a test sandbox and migrations that come out of the same package. Do not reach for it as a standalone SQL toolkit, because the pieces only make sense as part of Ecto. Before you commit, check the Ecto version in mix.lock against the adapters you plan to use, run mix test against a real Postgres or MySQL instance with ECTO_ADAPTER set, and read CHANGELOG.md for migration behaviour changes, since the repository has no GitHub releases to check against.
Frequently asked questions
Which databases does ecto_sql support out of the box?
The README lists default implementations for Postgres through Ecto.Adapters.Postgres, MySQL through Ecto.Adapters.MyXQL and MSSQL through Ecto.Adapters.Tds, with Ecto.Adapters.SQL as the entry point for all SQL based adapters.
How do I run the ecto_sql test suite against a specific database?
Set the ECTO_ADAPTER environment variable before running the suite, for example ECTO_ADAPTER=pg mix test. The values pg, myxql and tds correspond to the three built-in adapters and their integration test suites.
What does Ecto.Adapters.SQL.Sandbox do for tests?
It is a test sandbox that concurrently runs database tests inside transactions. Because it works against a real database server rather than an in-process substitute, tests built on it need Postgres, MySQL or MSSQL running locally.
How are database migrations handled in ecto_sql?
The README lists support for database migrations via Mix tasks, so migration commands run through the same mix toolchain as the rest of the project. The README does not document rollback behaviour or a migration naming convention.
Can ecto_sql be used without Ecto?
The package provides building blocks for writing SQL adapters for Ecto, and the README points to the Ecto repository for learning how to get started. It is designed as part of an Ecto application rather than as a standalone SQL library.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/elixir-ecto-ecto-sql)Was this useful?