- v2.0.0 (Oct 19, 2026)
- Breaking changes
- Drop SQLAlchemy 1.4 support: the dialect now requires
SQLAlchemy>=2.0.44,<2.1. SQLAlchemy 2.1.0 removedsqlalchemy.orm.context.ORMSelectCompileStateand changed other APIs the dialect and async shim import at module load time, so 2.1 is excluded. The internalsnowflake.sqlalchemy.compatmodule (SQLAlchemy 1.4/2.0 shim) was removed. Users still on SQLAlchemy 1.4 should pinsnowflake-sqlalchemy<2.0.0. - Require
snowflake-connector-python>=5.0.0(connector 5.x), which provides the async driver. Connector 4.x is no longer supported. - Supported Python versions are now 3.11–3.14 (drop 3.8, 3.9 and 3.10), since connector 5.x itself requires Python 3.11+. Updates
requires-python, Python classifiers, and mypy/ruff targets accordingly. enable_structured_type_jsonis on by default (see Features); explicitly setting it toFalserestores raw JSON strings and emits aDeprecationWarning(SNOW-3942921).- Remove the
force_div_is_floordivdialect flag. The/operator always performs true division (left / right) and//always performs floor division (FLOOR(left / right)). Passing the flag tocreate_engine()now raisesTypeError. Coming from a release older than 1.11.1, integer//previously compiled to plain/(true division in Snowflake) under the default flag value; it now floors (GH #756). - Remove the
legacy_url_paramsopt-out and itsSNOWFLAKE_SQLALCHEMY_LEGACY_URL_PARAMSenvironment variable. Passing it tocreate_engine()now raisesTypeErrorand the environment variable has no effect; sensitive connection parameters must be passed viaconnect_args=(SNOW-3942921).unsafe_skip_config_file_permissions_checkandcrl_unsafe_skip_file_permissions_checkare now also blocked from the URL query string.
- Drop SQLAlchemy 1.4 support: the dialect now requires
- Features
- Async support: the dialect now implements SQLAlchemy's
asyncioextension. Usecreate_async_engine()with the samesnowflake://URL as the sync dialect — there is no separate+driversuffix — to obtainAsyncEngine/AsyncSessionfor non-blocking database access. The async dialect checks forgreenletwhen the engine is created and raises anImportErrorwith install instructions. - Add the
enable_structured_type_jsondialect flag (URL parameter orcreate_engine(..., enable_structured_type_json=...), on by default). For semi-structuredVARIANT,OBJECTandARRAYcolumns, reading deserializes the JSON text Snowflake returns into native Python (dict/list/...), and writing nativedict/listvalues serializes them and wraps them inPARSE_JSON— rendered asINSERT ... SELECT(single row and multi-rowUNION ALL) since Snowflake rejects functions in aVALUESclause, and asSET col = PARSE_JSON(...)forUPDATE. Typed structured columns (MAP(...),ARRAY(<type>),OBJECT(...)with fields) are covered too: writes renderCAST(PARSE_JSON(...) AS <declared type>)and reads returndict/list. Element values are not converted to the declared types: they come back as JSON decodes them (for exampleMAP(NUMBER, ...)keys stay strings andDATEelements stay ISO strings). The engine'sjson_serializer/json_deserializerare used when provided (SNOW-1820647 / GH #107). - Support UUID and DECFLOAT values inside
VARIANTand structured types. Structured type compilers now compile their inner types against the Snowflake dialect, soARRAY/MAP/OBJECTelement, key and field types render consistently with standalone columns. The semi-structured JSON write path serializesdecimal.Decimalas a JSON string (preserving all 38 DECFLOAT digits, which a JSON number would truncate); reading one back requires an intermediate::VARCHARcast, since Snowflake rejects a directTEXT->DECFLOATcast onPARSE_JSONoutput (SNOW-4081644). - Add the opt-in
enable_native_uuiddialect flag (URL parameter orcreate_engine(..., enable_native_uuid=True)), which renders SQLAlchemy's genericUuidandMapped[uuid.UUID]as native SnowflakeUUIDinstead ofCHAR(32)and allowsuuid.UUIDinside semi-structured payloads.uuid.UUIDvalues are bound as strings and reads honouras_uuid(Truereturnsuuid.UUID,Falsereturnsstr). Off by default, since enabling it changes the DDL of existingUuidcolumns (SNOW-4081644). - Add strict host-name mode (
strict_host_names/SNOWFLAKE_SQLALCHEMY_STRICT_HOST_NAMES): the dialect no longer infers or appends domains to host names and forwards connection parameters, includingconnection_nameprofiles, to the connector unvalidated. Explicit stage endpoints are supported (SNOW-4248737). - Add
COLLATEsupport: expression-levelColumn.collate('<spec>')and column-type collation (String(collation='<spec>')) now render the collation as a single-quoted Snowflake string literal (e.g.COLLATE 'en-ci') instead of an invalid double-quoted identifier. Enables the SQLAlchemy suiteCollateTest(SNOW-629086). - Add subscript access for semi-structured columns:
col["key"]andcol[index]onVARIANT,OBJECT,ARRAYandMAPcolumns now compile to Snowflake's native bracket accessor (e.g.col['key'],col[0]), including nested chains such ascol["a"]["b"]. See Reading keys and elements with subscript access (SNOW-1820647 / GH #546). - Add support for Snowflake's multi-table
INSERT ALL/INSERT FIRSTstatements via the newInsertMulticustom command, including conditional (when/else_),OVERWRITE, and per-target column/value mapping (SNOW-782235 / GH #403). - Add support for row access policies on
SnowflakeTablevia therow_access_policyparameter; the policy name accepts a string (optionally fully qualified, e.g.'db.schema.policy') or asnowflake.sqlalchemy.FQN. See Row Access Policy Support (SNOW-884382 / GH #432). - Add opt-in
snowflake_rely=Trueto renderRELYonPRIMARY KEY/FOREIGN KEY/UNIQUEconstraints so the optimizer can trust them for query rewrites such as join elimination (SNOW-1023317 / GH #463). - Support
json_serializerandjson_deserializerparameters increate_engine, matching the built-in SQLAlchemy dialects (SNOW-889293 / GH #433). - Support
asdecimalparameter on_CUSTOM_DECIMALtype to allow opt-in conversion of numeric results to float instead of Decimal; default remains Decimal for backward compatibility (SNOW-728151 / GH #373). - Add a
python_typeproperty to Snowflake custom types (VARIANT,OBJECT,MAP,ARRAY,VECTOR,TIMESTAMP_*,GEOGRAPHY,GEOMETRY,DECFLOAT) for SQLAlchemy compatibility (SNOW-1866493 / GH #562). - Enhance
JSONFormatterwith the full SnowflakeTYPE=JSONoption set (date_format,time_format,timestamp_format,binary_format,trim_space,null_if,enable_octal,allow_duplicate,strip_outer_array,strip_null_values,replace_invalid_characters,ignore_utf8_errors,skip_byte_order_mark) (SNOW-589946). - Add
if_not_existsandcommentoptions toCreateFileFormatfor closer parity with Snowflake'sCREATE FILE FORMAT(SNOW-589962 / GH #291). - The dialect now sets
enable_server_session_keep_alive_auto_detection=Trueexplicitly on new connections. This pins the connector's present default so behaviour stays stable when that default changes, and silences the connector'sFutureWarning. A value supplied via the URL orconnect_argsstill takes precedence.
- Async support: the dialect now implements SQLAlchemy's
- Fixes
- Improve stage reference handling in compiled
COPY INTOand staged-file SQL (CWE-89):ExternalStagepaths, including sub-paths created withfrom_parent_stage, are rendered safely with escaping when quoting is required. Ordinary bare-path values retain their existing rendering (SNOW-4134196). - Fix NULL_IF backslash breakout in COPY FILE_FORMAT options (SNOW-4134195).
- Fix
repr()ofCopyIntoStorageunloading into anExternalStageor cloud location (AWSBucket,AzureContainer,GCSBucket), which raisedUnsupportedCompilationError; the target now uses its own secret-maskingrepr(). - Fix hybrid table index reflection: normalize reflected index names so unquoted identifiers round-trip in SQLAlchemy's lowercase convention (quoted/case-sensitive names preserved), preserve the caller's original schema (including
None) inget_multi_indexesresult keys so indexes attach when reflecting under the default schema, and return[]instead of['']for emptyINCLUDEcolumns (GH #755, fixes GH #754). - Fix
get_multi_indexes()raisingTypeErrorwhenfilter_namesisNone(e.g.Inspector.get_multi_indexes(schema=...)) and the schema contains Hybrid Tables; it now returns indexes for all Hybrid Tables in the schema. - Fix reflection failing on schemas/databases with more than 10,000 objects by paginating the underlying object-listing
SHOWcommands (get_table_names,get_view_names,get_temp_table_names,get_schema_names,get_sequence_names) withLIMIT ... FROM ...(SNOW-796954 / GH #406). - Fix PrivateLink/regional account parsing where org-style accounts with dashes (e.g.,
gnamsrm-vi65876.privatelink) were incorrectly truncated at the dash, breaking JWT/key-pair authentication. Account derivation now delegates to the Snowflake Connector's ownparse_account, so all host notations (plain, regional, regional/regionless PrivateLink, and.global) match the driver (SNOW-730644, also fixes SNOW-1209099). - Fix
URLfailing to encode[,],?and#in passwords, which produced connect strings that could not be parsed (SNOW-828206 / GH #415). - Fix invalid
LIMIT -1SQL generated for aSELECTwithOFFSETbut noLIMIT; theSnowflakeCompilernow emitsLIMIT NULL OFFSET ...as Snowflake requires (NO-SNOW / GH #745). - Detect expired-session/token and closed-connection errors, including error code
390195(authentication token expired, variant), as disconnects soconnection_invalidatedis set and pooled connections are recycled bypool_pre_ping(SNOW-669163 / GH #348, SNOW-3882904 / GH #702).
- Improve stage reference handling in compiled
- Documentation
- Add a migration guide from 1.x to 2.x and a contributing guide for local development setup, Hatch usage, and running tests.
- Document SSO/Okta authentication via the
authenticatorconnect_args parameter (SNOW-715550). - Document how to enable connector bulk array binding for large
executemanyinserts viaqmarkparamstyle (SNOW-710474). - Document using a SQLAlchemy
VALUESsource withMergeInto(no staging table needed) (SNOW-889678 / GH #435). - Document the raw-connector workaround for
PUTwith an in-memoryfile_stream(BytesIO) (SNOW-645168 / #337). - Document
CLUSTER BYusage in ORM/declarative models viaSnowflakeTable(SNOW-638838 / #313). - Document AUTOINCREMENT and IDENTITY column usage, including Sequence vs Identity trade-offs for Hybrid tables (SNOW-1232362).
- Document that Snowflake lacks
IS TRUE/IS FALSE; usecol == true()/col == false()(#680).
- Breaking changes