You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the feature you'd like to see implemented
This RFC sets out the public API for vector support in Sequelize v7. #18227 by @prajalg started it, with an Oracle implementation. This RFC turns that work into an API that fits the other dialects too.
Everything below is a proposal open for discussion. @prajalg, and anyone else interested in vector support, please comment here: questions, objections and better ideas are all welcome. The aim is for this issue to be the one place future dialect PRs (pgvector, MariaDB, SQL Server, Db2, …) can point to.
Delivery plan
Vector support ships as a stack of Oracle-first PRs. Each one is reviewable and mergeable on its own:
sql.vectorDistance, the distance expression, with the Oracle implementation.
Vector indexes, with the Oracle implementation.
Between these PRs, maintainers plan to prototype pgvector, and possibly other dialects, against the abstraction before PR 2 and PR 3 are final. That isn't expected from the PR author.
1. Data type
DataTypes.VECTOR// float32, dimensions optional where supportedDataTypes.VECTOR(1536)// float32DataTypes.VECTOR({dimensions: 1536,elementType: 'int8'})DataTypes.VECTOR({dimensions: 1536,typedArray: true})// read as Float32Array instead of number[]typeVectorElementType='float16'|'float32'|'float64'|'int8'|'binary';
Options.dimensions and elementType. The element type is a closed, typed union, so arbitrary strings aren't accepted. There's no positional element-type argument.
Default element type.float32, rendered explicitly. On Oracle, VECTOR(768) becomes VECTOR(768, FLOAT32), not Oracle's "any format".
Omitting dimensions. Allowed only where the dialect supports flexible dimensions (Oracle renders VECTOR(*, FLOAT32)). Elsewhere it throws.
Sparse vectors: a separate SPARSE_VECTOR type may come later.
Oracle's "any element type" column (VECTOR(*, *)).
An int32 element type (only Snowflake has one).
Capability flag. This uses the same pattern as DECIMAL and INTS. Maximum dimensions are tracked per element type, because they differ, e.g. SQL Server float32 1998 vs float16 3996.
Writes accept number[] or the typed array for the element type (Float32Array, Float64Array, Int8Array).
Reads return number[] by default on every dialect, so values are JSON-safe and match what embedding APIs produce. Each dialect's parseDatabaseValue normalises to this.
typedArray: true (per attribute) makes reads return the typed array for the element type. With the opt-in, float16 reads as Float32Array, because Float16Array isn't available on Node 22.
binary vectors are always a packed Uint8Array (dimensions / 8 bytes), on both read and write.
Change tracking. Values are compared element-wise across array kinds, so reloading a row and setting an equal array doesn't mark the attribute as changed.
Dialects that can't bind a vector as is wrap the bind parameter through the data type's getBindParamSql (e.g. CAST(@p AS VECTOR(n))), bulk inserts included.
A sql.* builder built on DialectAwareFn, like sql.random and sql.unquote. There are no sequelize.* instance methods and, for now, no per-metric aliases.
The metric is required. There's no "default metric", because on Oracle and MariaDB the default depends on which index exists.
Every metric returns a distance (smaller means closer, so ASC gives the nearest rows) on every dialect. 'dot' is the negative inner product, following Oracle DOT, SQL Server 'dot' and pgvector <#>. Where a dialect only has a similarity, the builder emulates the distance (e.g. Snowflake 1 - VECTOR_COSINE_SIMILARITY).
Operands.
The left operand must be an Expression, typically sql.attribute('embedding'), which handles field mapping, aliases and $include.attr$. A raw string throws with a hint.
The right operand can be an expression (column vs column works) or a literal vector. A literal vector is bound (or escaped) through the VECTOR data type, never inlined as text.
Rendering must be "bare" and match the index. No wrapper or cast on the column side; pgvector uses the operator form (<=>); Oracle uses VECTOR_DISTANCE(col, :q, COSINE). This way vector indexes can be used.
Capability flag, separate from the data type (MySQL Community has the type but no distance functions):
No Sequelize-side check that a metric fits an element type (e.g. jaccard on float32). The database raises that error.
Raw sql.fn('VECTOR_DISTANCE', …) keeps working unchanged, as the escape hatch for dialect-specific forms.
4. Vector indexes
indexes: [{fields: ['embedding'],type: 'VECTOR',vector: {metric: 'cosine',method: 'hnsw',// 'hnsw' | 'ivfflat' | 'diskann', per dialectparameters: {m: 16,efConstruction: 64},// portable names, translated per dialectdialectOptions: {targetAccuracy: 95},// dialect-only options, validated by the dialect},}]supports.index.vector: false|{methods: readonlystring[]; metrics: readonlyVectorMetric[]};
Options are nested under vector and typed.
Portable parameter names (m, efConstruction, lists) are mapped to each dialect's keyword, e.g. Oracle NEIGHBORS/EFCONSTRUCTION/NEIGHBOR PARTITIONS, pgvector m/ef_construction/lists, MariaDB M=. Anything else goes in dialectOptions.
Unsupported or unknown keys, and parameters that don't fit the chosen method, throw.
pgvector derives the operator class (e.g. vector_cosine_ops) from the column type and metric when the type is known, and requires an explicit operator otherwise.
Where supports.index.vector is false, core throws on type: 'VECTOR', instead of building a regular index or emitting invalid SQL.
5. Server versions and runtimes
Every dialect with vectors needs a server above Sequelize's minimum, or an extension: Oracle 23.4, MySQL 9.0, MariaDB 11.7, SQL Server 2025, Db2 12.1.2, pgvector, sqlite-vec.
For now, capability flags stay static, and each feature documents its minimum server version. Version-, extension- and runtime-aware capabilities are discussed separately in #18449.
6. Tests
Public SQL output (DDL, index SQL, distance SQL) is tested in core, on all dialects, with expectsql per-dialect expectations. Unsupported dialects are expected to throw.
Behaviour is tested by one shared core integration suite, gated on the capability flags. It covers round trips, read types, change tracking, distance semantics per metric, attribute mapping, includes, bulkCreate, sync({ alter }) and realistic (1536-dimension) queries, and skips when the server is too old or an extension is missing. Every dialect that enables vectors gets this suite automatically.
four types (vector, halfvec, bit, sparsevec), operators, operator classes
2
MariaDB 11.7+
cosine and euclidean only; one vector index per table
2
SQL Server 2025
bind needs a cast; approximate search only through VECTOR_SEARCH
3
Db2 12.1.2+
VECTOR(?, n, FLOAT32) constructor for binds; indexes need 12.1.5
4
MySQL 9
type only; distance functions are HeatWave-only
–
Snowflake
only if there's demand
–
SQLite, IBM i
not supported for now (sqlite-vec is an extension that works through virtual tables; IBM i has no vector type)
8. Later work (out of scope)
Approximate-search queries. For example, a findAll option that emits FETCH APPROX on Oracle and Db2 and SET LOCAL hnsw.ef_search on pgvector. SQL Server's VECTOR_SEARCH is a separate design question. A tracking issue will follow once the distance expression lands.
Sparse vectors, as SPARSE_VECTOR.
Similarity builders (positive dot product, cosine similarity), if people ask for them.
Describe why you would like this feature to be added to Sequelize
Vector search is now built into Oracle, PostgreSQL (pgvector), MariaDB, MySQL, SQL Server, Db2 and Snowflake. Storing embeddings next to relational data and querying them through the ORM is an increasingly common need. A single, consistent API, one where the same findAll means the same thing and can use an index on every database, only works if it's designed across dialects from the start, before the first implementation freezes it.
Is this feature dialect-specific?
No. This feature is relevant to Sequelize as a whole.
Yes. This feature only applies to the following dialect(s):
Would you be willing to resolve this issue by submitting a Pull Request?
No, I don't have the time, and I understand that I will need to wait until someone from the community or maintainers is interested in implementing my feature.
The Oracle implementation is in progress in #18227.
Indicate your interest in the addition of this feature by adding the 👍 reaction. Comments such as "+1" will be removed.
Issue Creation Checklist
Feature Description
Describe the feature you'd like to see implemented
This RFC sets out the public API for vector support in Sequelize v7. #18227 by @prajalg started it, with an Oracle implementation. This RFC turns that work into an API that fits the other dialects too.
Everything below is a proposal open for discussion. @prajalg, and anyone else interested in vector support, please comment here: questions, objections and better ideas are all welcome. The aim is for this issue to be the one place future dialect PRs (pgvector, MariaDB, SQL Server, Db2, …) can point to.
Delivery plan
Vector support ships as a stack of Oracle-first PRs. Each one is reviewable and mergeable on its own:
DataTypes.VECTOR+ the Oracle implementation. feat(core): add VECTOR datatype support with Oracle vector integration #18227 would be reduced to this.sql.vectorDistance, the distance expression, with the Oracle implementation.Between these PRs, maintainers plan to prototype pgvector, and possibly other dialects, against the abstraction before PR 2 and PR 3 are final. That isn't expected from the PR author.
1. Data type
dimensionsandelementType. The element type is a closed, typed union, so arbitrary strings aren't accepted. There's no positional element-type argument.float32, rendered explicitly. On Oracle,VECTOR(768)becomesVECTOR(768, FLOAT32), not Oracle's "any format".dimensions. Allowed only where the dialect supports flexible dimensions (Oracle rendersVECTOR(*, FLOAT32)). Elsewhere it throws.storageorsparsethrow rather than being silently dropped. See also Validate options at runtime: reject unsupported and unknown options, stricter typings #18450.dimensionswhen it's set.SPARSE_VECTORtype may come later.VECTOR(*, *)).int32element type (only Snowflake has one).Capability flag. This uses the same pattern as
DECIMALandINTS. Maximum dimensions are tracked per element type, because they differ, e.g. SQL Server float32 1998 vs float16 3996.2. Values in and out
number[]or the typed array for the element type (Float32Array,Float64Array,Int8Array).number[]by default on every dialect, so values are JSON-safe and match what embedding APIs produce. Each dialect'sparseDatabaseValuenormalises to this.typedArray: true(per attribute) makes reads return the typed array for the element type. With the opt-in,float16reads asFloat32Array, becauseFloat16Arrayisn't available on Node 22.binaryvectors are always a packedUint8Array(dimensions / 8 bytes), on both read and write.getBindParamSql(e.g.CAST(@p AS VECTOR(n))), bulk inserts included.3. Distance expression
sql.*builder built onDialectAwareFn, likesql.randomandsql.unquote. There are nosequelize.*instance methods and, for now, no per-metric aliases.ASCgives the nearest rows) on every dialect.'dot'is the negative inner product, following OracleDOT, SQL Server'dot'and pgvector<#>. Where a dialect only has a similarity, the builder emulates the distance (e.g. Snowflake1 - VECTOR_COSINE_SIMILARITY).Expression, typicallysql.attribute('embedding'), which handlesfieldmapping, aliases and$include.attr$. A raw string throws with a hint.<=>); Oracle usesVECTOR_DISTANCE(col, :q, COSINE). This way vector indexes can be used.jaccardon float32). The database raises that error.sql.fn('VECTOR_DISTANCE', …)keeps working unchanged, as the escape hatch for dialect-specific forms.4. Vector indexes
vectorand typed.m,efConstruction,lists) are mapped to each dialect's keyword, e.g. OracleNEIGHBORS/EFCONSTRUCTION/NEIGHBOR PARTITIONS, pgvectorm/ef_construction/lists, MariaDBM=. Anything else goes indialectOptions.vector_cosine_ops) from the column type and metric when the type is known, and requires an explicitoperatorotherwise.supports.index.vectoris false, core throws ontype: 'VECTOR', instead of building a regular index or emitting invalid SQL.5. Server versions and runtimes
Every dialect with vectors needs a server above Sequelize's minimum, or an extension: Oracle 23.4, MySQL 9.0, MariaDB 11.7, SQL Server 2025, Db2 12.1.2, pgvector, sqlite-vec.
For now, capability flags stay static, and each feature documents its minimum server version. Version-, extension- and runtime-aware capabilities are discussed separately in #18449.
6. Tests
expectsqlper-dialect expectations. Unsupported dialects are expected to throw.bulkCreate,sync({ alter })and realistic (1536-dimension) queries, and skips when the server is too old or an extension is missing. Every dialect that enables vectors gets this suite automatically.packages/<dialect>/src/*.test.ts. Dialect-only DB checks stay inpackages/core/test/integration/dialects/<dialect>/for now; see Dialect-package tests: DB-backed tests next to the dialect, and a reusable conformance suite for third-party dialects #18451.7. Dialect roadmap (after Oracle)
vector,halfvec,bit,sparsevec), operators, operator classesVECTOR_SEARCHVECTOR(?, n, FLOAT32)constructor for binds; indexes need 12.1.58. Later work (out of scope)
findAlloption that emitsFETCH APPROXon Oracle and Db2 andSET LOCAL hnsw.ef_searchon pgvector. SQL Server'sVECTOR_SEARCHis a separate design question. A tracking issue will follow once the distance expression lands.SPARSE_VECTOR.Describe why you would like this feature to be added to Sequelize
Vector search is now built into Oracle, PostgreSQL (pgvector), MariaDB, MySQL, SQL Server, Db2 and Snowflake. Storing embeddings next to relational data and querying them through the ORM is an increasingly common need. A single, consistent API, one where the same
findAllmeans the same thing and can use an index on every database, only works if it's designed across dialects from the start, before the first implementation freezes it.Is this feature dialect-specific?
Would you be willing to resolve this issue by submitting a Pull Request?
The Oracle implementation is in progress in #18227.
Indicate your interest in the addition of this feature by adding the 👍 reaction. Comments such as "+1" will be removed.