activerecord-sqlserver-adapter: Rails on SQL Server, branch by branch
SQL Server Adapter For Rails
At a glance
- What is it?
- The activerecord-sqlserver-adapter gem lets a Rails application talk to SQL Server through ActiveRecord, with native unicode types, TinyTDS under the hood and a stable branch per Rails release. The sharp edges are the ones SQL Server itself creates: triggers versus OUTPUT INSERTED, datetime precision, and the end of support for older Rails lines.
- Who is it for?
- Adopt this adapter when your Rails application has to live on SQL Server and you want ActiveRecord rather than a second persistence layer, and pick the branch that matches your Rails version instead of main. Do not adopt it for a new project that could start on another database, or if your tables rely on triggers without the exclude_output_inserted_table_names workaround.
- Can I use it commercially?
- Yes. MIT 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 7 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The bridge between ActiveRecord and SQL Server 2012 or later
activerecord-sqlserver-adapter is a Ruby gem that plugs SQL Server into ActiveRecord, so a Rails application can use a Microsoft database without giving up the ORM, the migrations and the query builder that the rest of the framework depends on. The scope is stated plainly in the project documentation: the SQL Server adapter for ActiveRecord using SQL Server 2012 or higher. That version floor is a hard requirement, not a preference.
The intended audience is Rails teams with an existing SQL Server estate. Legacy schemas that cannot move, corporate database mandates, or an organisation that already runs SQL Server for its reporting and finance systems. For those teams the alternative is usually a second persistence path alongside ActiveRecord, which is exactly the duplication this gem exists to remove.
The implementation is a thin but opinionated layer over a driver rather than a reimplementation of the protocol. The dependency set names TinyTDS as the driver, the FreeTDS library underneath it, and the gem is distributed as activerecord-sqlserver-adapter, with a gemspec and a Gemfile at the root of the repository. The Ruby code lives under lib/, the test suite under test/, and there is a guides directory alongside a separate RUNNING_UNIT_TESTS.md for people who want to run the suite themselves.
One stable branch per Rails release, and a support table to match
The versioning policy is the first thing to read, and it is stricter than most gem maintainers use. The project follows a rational versioning policy that tracks Rails, which means the 7.x version of the adapter is only for the latest 7.x version of Rails, and there are stable branches for each major and minor release of ActiveRecord.
The table in the project documentation makes the current state explicit. The Unreleased row targets Rails 8.2.x and lives on main, and its support column reads In Development. The 8.1.x and 8.0.x adapter lines are Active and live on the 8-1-stable and 8-0-stable branches. Every older line, from 7.2.x down to 4.1.x, is marked Ended, each with its own archived branch.
Support is tied to the Rails Bug Fixes maintenance group, so the set of adapter versions receiving fixes follows whatever Rails itself is still patching. The practical consequence for an upgrade is that you are not choosing a gem version on your own schedule; you are choosing the branch that matches the Rails version you intend to run, and then moving both together. Rubygems carries the latest adapter version for each Rails release, which is the list to consult when you plan that move.
TDS 7.3 is the floor for date and time columns
The driver stack has a hard requirement that is easy to miss. Four column types, date, datetime2, datetimeoffset and time, all require TDS version 7.3 with TinyTDS. The project recommends FreeTDS 1.0 or higher, which defaults to using TDSVER to 7.3, and notes that the adapter also sets TinyTDS's tds_version to this when none is specified.
So a driver configuration that pins an older protocol version will fail on those types even though the adapter itself is configured correctly. The place to check is the FreeTDS configuration on the machine running the application, not the Rails config. If a deployment uses an older FreeTDS and a date column is involved, that combination is the first suspect.
Type mapping is handled for you in the general case. The adapter supports every data type supported by FreeTDS, and all simplified Rails types in migrations correspond to a matching SQL Server national, unicode data type. The concrete list lives in NATIVE_DATABASE_TYPES in the adapter source file, and the documentation points at that file as the authoritative place to look rather than reproducing the list, on the reasonable ground that it changes as the adapter tracks new SQL Server capabilities.
Datetime precision decides between datetime and datetime2
The adapter supports ActiveRecord's datetime_with_precision setting, so passing :precision to a datetime column is supported. The default is precision 6 for :datetime types when precision is not specified, and any non-nil precision tells the adapter to use the datetime2 column type.
The edge case is the one that surprises people. To create a datetime column rather than datetime2, a migration has to specify a precision of nil. Leave it unspecified and precision defaults to 6, which means you get a datetime2 column instead. That difference matters when an existing schema, a reporting tool or a migration written for another adapter expects the older type, and it is invisible in the migration file itself unless someone reads the type mapping.
The same mechanism runs in the other direction too. Once a precision is set on a column, the adapter maps it to datetime2, which is the type with the wider range and precision. For a new project this is the behaviour you probably want and the simplest path is to let the default stand. For a project migrating an existing database, the nil precision is the switch that keeps a legacy column type intact.
OUTPUT INSERTED and tables with triggers
The adapter uses OUTPUT INSERTED so that it can select any data type key, for example in UUID tables. That approach is efficient and type agnostic, and it is the mechanism behind getting generated keys back from an insert. The project documentation is clear that it poses a problem with tables that use triggers, because the OUTPUT clause and the trigger's own result set can collide.
The workaround is a more complex insert statement that uses a temporary table to select the inserted identity, and to use it you must declare the table exempt from the simple OUTPUT INSERTED style by putting the table name into a concurrent hash. The example in the documentation shows the three forms you can use:
adapter = ActiveRecord::ConnectionAdapters::SQLServerAdapter
# Will assume `bigint` as the id key temp table type.
adapter.exclude_output_inserted_table_names['my_table_name'] = true
# Explicitly set the data type for the temporary key table.
adapter.exclude_output_inserted_table_names['my_uuid_table_name'] = 'uniqueidentifier'You can also set data types explicitly when the data type differs for composite primary keys, by assigning a hash of column names and types to the same key. The default assumption is bigint for the temporary key table, so a table whose identity is a uniqueidentifier or a composite key needs the explicit form.
This is the sharpest edge in the whole adapter. It is a per table opt in, it has to be applied in an initializer or wherever the adapter object is reachable, and a table with a trigger that nobody flagged will fail in a way that looks like an insert problem rather than a configuration one.
Schema prefixes, forced lowercase and a configure_connection hook
Three configuration points cover most of what a team needs to adjust, and all three live in an initializer rather than in the database configuration.
Depending on the user and schema setup, it may be needed to use a table name prefix of dbo., which is set on ActiveRecord::Base.table_name_prefix. The documentation also shows how schemas are created, moved and dropped from a migration, using create_schema('foo'), change_table_schema('foo', 'dbo.admin') and drop_schema('foo').
For naming conventions, the adapter can force all table and column names during the schema reflection process to be lowercase, which is useful when the database schema is in upper or mixed case:
ActiveRecord::ConnectionAdapters::SQLServerAdapter.lowercase_schema_reflection = trueFinally, the adapter conforms to the AbstractAdapter interface to configure connections, and if you require additional connection configuration you implement the configure_connection method in an initializer. The documented example sets TEXTSIZE to 64 megabytes, which matters when a query returns large result sets that would otherwise be truncated by the driver's default packet size. The same hook is where you would set anything else the driver's connection exposes.
CI in containers, no GitHub releases, MIT licence
The repository has no GitHub releases, so the version history lives in the tags and in CHANGELOG.md rather than on a release page. It is not archived and the last push was on 2026-10-16, so maintenance is current.
The project tests in containers. There is a Dockerfile.ci, a compose.ci.yaml and a .devcontainer directory, along with a CI workflow badge pointing at the ci.yml workflow, and older CI configuration in appveyor.yml. A Rakefile, a Guardfile and the RUNNING_UNIT_TESTS.md document explain how to run the suite. AGENTS.md and CODE_OF_CONDUCT.md sit at the root, and .rubocop.yml governs style.
Licensing is the simplest part of the picture. The gem is released under the MIT licence, with the MIT-LICENSE file at the repository root. MIT is permissive and carries no copyleft obligation, so embedding the adapter in a commercial application raises no source disclosure requirement for the adapter itself. That is a reading of the licence terms only, and it says nothing about the SQL Server licence you need for the database itself.
Editorial conclusion
Adopt this adapter when your Rails application has to live on SQL Server and you want ActiveRecord rather than a second persistence layer, and pick the branch that matches your Rails version instead of main. Do not adopt it for a new project that could start on another database, or if your tables rely on triggers without the exclude_output_inserted_table_names workaround. Verify first that SQL Server is 2012 or later, that your FreeTDS install defaults to TDS 7.3, and that the adapter version you pin is still in the Rails Bug Fixes maintenance group.
Frequently asked questions
Which SQL Server versions does activerecord-sqlserver-adapter support?
The project documentation states that the adapter is for ActiveRecord using SQL Server 2012 or higher. Older server versions are outside the supported range.
Which branch of activerecord-sqlserver-adapter should I use for my Rails version?
Pick the branch that matches your Rails version: 8-1-stable for Rails 8.1.x, 8-0-stable for 8.0.x, and main for the unreleased 8.2.x line. Adapter versions marked Ended in the support table, from 7.2.x downwards, are no longer supported.
Why do my date columns fail or turn into datetime2 in activerecord-sqlserver-adapter?
The date, datetime2, datetimeoffset and time types require TDS version 7.3 with TinyTDS, so FreeTDS 1.0 or higher is recommended. Separately, a datetime column without an explicit precision defaults to precision 6, which creates a datetime2 column, so specify a precision of nil to get a plain datetime.
How do I handle tables with triggers in activerecord-sqlserver-adapter?
Because the adapter uses OUTPUT INSERTED, tables with triggers need the more complex insert path. Declare them in the exclude_output_inserted_table_names concurrent hash, using true for a bigint identity, a type name such as 'uniqueidentifier', or a hash of column names and types for composite primary keys.
Can activerecord-sqlserver-adapter use a non default schema?
Yes. Set a table name prefix such as 'dbo.' with ActiveRecord::Base.table_name_prefix, and use create_schema, change_table_schema and drop_schema inside migrations to manage schemas.
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/rails-sqlserver-activerecord-sqlserver-adapter)Was this useful?