ArrowTDS
v0.5.25Linux · Windows (x64)Azure SQL · Microsoft Fabric
A pure-native ADBC driver for Microsoft SQL Server that speaks MS-TDS 7.4
directly over TCP/TLS and delivers Apache Arrow RecordBatches end to end.
OpenSSL is the only runtime dependency beyond libc — no ODBC, no SQL Server client
libraries. It also covers Azure SQL and Microsoft Fabric Warehouse.
note
Reading these docs. The badge above is the version this documentation describes. Options and features added recently are flagged inline with a Since vX.Y.Z note; the What's new page is the release-by-release view. See Versioning.
Highlights
- Native TDS 7.4 over TCP/TLS — SQL Server 2012–2025, Azure SQL, Fabric.
- Every auth mode — SQL logins, trusted/integrated (Windows SSPI; POSIX Kerberos via GSSAPI/SPNEGO), and Microsoft Entra ID.
- Rich type mapping — including SQL Server 2025
VECTOR(n)→ Arrowfixed_size_list, andgeometry/geography→ GeoArrow WKB. - Arrow straight from the wire — results decode into Arrow column buffers with no intermediate row objects.
Connect in seconds
Load the driver by name (arrowtds) from any ADBC client:
- Python
- C / C++
- C#
- Go
- Java
- R
- Rust
import adbc_driver_manager.dbapi as dbapi
with dbapi.connect(driver="arrowtds",
db_kwargs={"uri": "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true"}) as conn:
cur = conn.cursor()
cur.execute("SELECT * FROM dbo.orders")
table = cur.fetch_arrow_table()
#include <arrow-adbc/adbc.h>
// (error checks elided for brevity)
AdbcError e = {}; AdbcDatabase db = {}; AdbcConnection conn = {}; AdbcStatement st = {};
AdbcDatabaseNew(&db, &e);
AdbcDatabaseSetOption(&db, "driver", "arrowtds", &e);
AdbcDatabaseSetOption(&db, "uri", "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true", &e);
AdbcDatabaseInit(&db, &e);
AdbcConnectionNew(&conn, &e); AdbcConnectionInit(&conn, &db, &e);
AdbcStatementNew(&conn, &st, &e);
AdbcStatementSetSqlQuery(&st, "SELECT * FROM dbo.orders", &e);
ArrowArrayStream stream = {}; int64_t n = -1;
AdbcStatementExecuteQuery(&st, &stream, &n, &e); // consume `stream`
using Apache.Arrow.Adbc;
using Apache.Arrow.Adbc.DriverManager;
using var driver = AdbcDriverManager.FindLoadDriver("arrowtds", loadOptions: AdbcLoadFlags.Default);
using var database = driver.Open(new Dictionary<string, string> {
["uri"] = "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true" });
using var connection = database.Connect(null);
using var statement = connection.CreateStatement();
statement.SqlQuery = "SELECT * FROM dbo.orders";
using var stream = statement.ExecuteQuery().Stream!; // IArrowArrayStream
var drv drivermgr.Driver
db, _ := drv.NewDatabase(map[string]string{
"driver": "arrowtds",
adbc.OptionKeyURI: "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true",
})
conn, _ := db.Open(ctx)
stmt, _ := conn.NewStatement()
_ = stmt.SetSqlQuery("SELECT * FROM dbo.orders")
reader, _, _ := stmt.ExecuteQuery(ctx) // array.RecordReader
defer reader.Release()
Map<String, Object> params = new HashMap<>();
JniDriver.PARAM_DRIVER.set(params, "arrowtds");
AdbcDriver.PARAM_URI.set(params, "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true");
try (BufferAllocator a = new RootAllocator();
AdbcDatabase db = new JniDriver(a).open(params);
AdbcConnection conn = db.connect();
AdbcStatement st = conn.createStatement()) {
st.setSqlQuery("SELECT * FROM dbo.orders");
try (AdbcStatement.QueryResult r = st.executeQuery()) {
ArrowReader reader = r.getReader();
}
}
library(adbcdrivermanager)
db <- adbc_database_init(adbc_driver("arrowtds"),
uri = "sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true")
con <- adbc_connection_init(db)
table <- read_adbc(con, "SELECT * FROM dbo.orders") |> arrow::as_arrow_table()
use adbc_core::{Connection, Database, Driver, Statement, LOAD_FLAG_DEFAULT};
use adbc_core::options::{AdbcVersion, OptionDatabase, OptionValue};
use adbc_driver_manager::ManagedDriver;
let mut driver = ManagedDriver::load_from_name("arrowtds", None, AdbcVersion::default(), LOAD_FLAG_DEFAULT, None)?;
let mut db = driver.new_database_with_opts([(OptionDatabase::Uri,
OptionValue::String("sqlserver://sa:<pw>@host:1433/?database=db&encrypt=true".into()))])?;
let mut conn = db.new_connection()?;
let mut stmt = conn.new_statement()?;
stmt.set_sql_query("SELECT * FROM dbo.orders")?;
let reader = stmt.execute()?; // impl RecordBatchReader
New here? Install ArrowTDS first, then see the Connection guide.
All ArrowTDS pages
ConnectionOptions, connection strings, URIs, named instances, Azure & Entra.AuthenticationSQL, trusted/integrated (SSPI, Kerberos), Entra ID.Data typesSQL Server ↔ Arrow mapping, temporal precision, geospatial, VECTOR.CompatibilitySupported versions, editions, Azure/Fabric, platforms, conformance.ExamplesCopy-paste recipes: query to Arrow/pandas/Polars/DuckDB, bind, ingest.Environment variablesDriver-specific
ARROWTDS_* knobs and build-time overrides.LicensingSupplying and checking your Arpeio licence.TroubleshootingConnect, TLS, auth, licence and ingest failures and fixes.What's newReader-facing release highlights.