Skip to main content

Velr

Velr is an embedded property-graph database from Velr.ai, written in Rust, built on top of SQLite (persisting to a standard SQLite database file) and queried using the openCypher language.

It runs in-process and is designed for local, embedded, and edge use cases.

This package provides the Python bindings for Velr. It exposes a small, Pythonic API for executing Cypher queries, iterating result tables, working with transactions, and exporting results to Arrow, pandas, and Polars.

For the main Velr public entry point, see velr-ai/velr.
For the Velr website, see velr.ai.

Community

We’d love to have you join the Velr community.


Release status

Velr is currently in public alpha.

  • The Python API is still evolving.
  • Velr supports openCypher and passes all positive openCypher TCK tests. Exact error semantics are not guaranteed to match other openCypher implementations.
  • Velr 0.2.14 includes a breaking on-disk storage change; existing databases from earlier releases must be recreated by re-importing the source data.
  • Starting with the 0.3.x series, we intend to guarantee internal database compatibility within the branch.

Schema version 9 compatibility

This release uses on-disk schema version 9. Database files at supported schema versions 8 or earlier can still be opened for reads without changing the file, but they must be explicitly migrated to schema version 9 before writes or features that require the current schema. Opening a database never migrates it automatically.

Velr is already usable for real workflows and representative use cases, but rough edges remain and the API is not yet stable.

Fulltext search and vector search are available today through Cypher DDL and CALL syntax. API details may still evolve while Velr remains alpha.


Installation

Install from PyPI:

pip install velr

For Arrow / dataframe workflows, install the optional Python dependencies you want to use:

pip install pyarrow pandas polars

Licensing in simple terms

  • The Python binding source code in this package is licensed under MIT.
  • The bundled native runtime binaries may be used and freely redistributed in unmodified form under the terms of LICENSE.runtime.

Quick start

from velr.driver import Velr

MOVIES_CREATE = r"""
CREATE
  (keanu:Person:Actor {name:'Keanu Reeves', born:1964}),
  (nolan:Person:Director {name:'Christopher Nolan'}),
  (matrix:Movie {title:'The Matrix', released:1999, genres:['Sci-Fi','Action']}),
  (inception:Movie {title:'Inception', released:2010, genres:['Sci-Fi','Heist']}),
  (keanu)-[:ACTED_IN {roles:['Neo']}]->(matrix),
  (nolan)-[:DIRECTED]->(inception);
"""

with Velr.open(None) as db:
    db.run(MOVIES_CREATE)

    with db.exec_one(
        "MATCH (m:Movie {title:'Inception'}) "
        "RETURN m.title AS title, m.released AS year, m.genres AS genres"
    ) as table:
        print(table.column_names())

        with table.iter_rows() as rows:
            row = next(rows)

    title, year, genres = row
    print(title.as_python())
    print(year.as_python())
    print(genres.as_python())

Open a file-backed database instead of an in-memory database:

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    db.run("CREATE (:Person {name:'Alice'})")

Open an existing database for reads only:

from velr.driver import Velr

with Velr.open_readonly("mygraph.db") as db:
    with db.exec_one("MATCH (n) RETURN count(n) AS count") as table:
        print(table.collect(lambda row: [cell.as_python() for cell in row]))

open_readonly() never creates, initializes, migrates, or repairs a database. The file must already exist and have a supported Velr schema version. Older supported databases, such as schema version 3, 4, 5, 6, 7, or 8 databases opened by a schema version 9 runtime, remain available for reads. Writes and features that require the current schema fail with a normal query error until the database is explicitly migrated.


Schema migration

Velr does not migrate supported older databases automatically on open. Use the driver migration API, or run MIGRATE DATABASE, from maintenance code when you intend to update the on-disk schema. See the release-status note above for the schema version 9 read/write compatibility behavior.

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    if db.needs_migration():
        report = db.migrate()
        print(report.status, report.from_version, report.to_version, report.steps)

The equivalent Cypher command is useful for scripts and tools that already work through query execution:

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    with db.exec_one("MIGRATE DATABASE") as table:
        print(table.collect(lambda row: [cell.as_python() for cell in row]))

Maintenance

After large deletes or prune operations on a file-backed database, call db.vacuum() from maintenance code when you want to compact the database file:

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    db.run("MATCH (n:Expired) DETACH DELETE n")
    db.vacuum()

vacuum() must run on a writable current-schema connection outside an open transaction. The equivalent command for scripts is VACUUM DATABASE.


Introspection

Use SHOW CURRENT GRAPH SHAPE to inspect the observed schema of the graph. It reports the shape present in stored data: node labels, relationship types, properties, observed value types, and counts. It is an observed shape surface, not a declared GQL graph type.

SHOW CURRENT GRAPH SHAPE is available on schema version 5 or newer databases. Older supported databases can still be opened for reads, but must be migrated explicitly before this command is valid. Schema version 5 introduced this inventory through the write planner instead of persistent graph-shape triggers.

The default projection returns element_kind, element_name, property_name, observed_type, owner_count, present_count, and missing_count. YIELD * exposes the full row shape, including surface, source_label, target_label, required, storage_class, and tag.

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    with db.exec_one(
        """
        SHOW CURRENT GRAPH SHAPE
        YIELD element_kind, element_name, property_name, observed_type, owner_count
        WHERE element_kind = 'node_property'
        RETURN element_name, property_name, observed_type, owner_count
        """
    ) as table:
        with table.iter_rows() as rows:
            for row in rows:
                print([cell.as_python() for cell in row])

Use YIELD to compose the command with WHERE and RETURN. Plain SHOW CURRENT GRAPH SHAPE returns the default projection; YIELD * exposes the full current row shape.


Fulltext search is available through normal Cypher execution. Define indexes with CREATE FULLTEXT INDEX and query them with CALL db.index.fulltext.queryNodes(...).

from velr.driver import Velr

with Velr.open("mygraph.db") as db:
    db.run(
        """
        CREATE FULLTEXT INDEX paperText
        FOR (n:Paper) ON EACH [n.title, n.abstract]
        """
    )

    with db.exec_one(
        """
        CALL db.index.fulltext.queryNodes('paperText', 'abstract:vector')
        YIELD node, score
        RETURN node, score
        """
    ) as table:
        with table.iter_rows() as rows:
            for row in rows:
                print([cell.as_python() for cell in row])

The query string supports this fulltext grammar:

  • Terms: vector search
  • Phrases: "vector search"
  • Field scoping by indexed property: title:graph, abstract:"vector search"
  • Boolean operators and grouping: graph AND (vector OR semantic)
  • Default OR between adjacent terms: vector search
  • Required and excluded terms: +vector -draft
  • Phrase slop: "vector search"~2
  • Phrase prefix on the last phrase term: "vector sea"*
  • Boosts: title:graph^2.0
  • Match all indexed nodes: *

Field scoping applies to the next term or phrase only. For example, title:graph search searches graph in title and search in the default fulltext field.

score is a non-normalized relevance score. Higher scores are better within a single query result set; scores are not guaranteed to be in 0..1 or comparable across different queries.

Fulltext indexes are kept up to date by writes. For file-backed databases, Velr repairs missing or corrupt fulltext index data automatically when the database is opened.


Velr supports two vector index shapes.

If your application already computes embeddings, store them as a vector/list property and index that property. No embedder is needed, and queries pass a numeric vector/list:

with Velr.open("mygraph.db") as db:
    db.run(
        """
        CREATE (:Chunk {
          id: 'chunk-1',
          text: 'Graph databases store connected data',
          embedding: [0.12, 0.34, 0.56]
        })
        """
    )

    db.run(
        """
        CREATE VECTOR INDEX chunkEmbedding IF NOT EXISTS
        FOR (n:Chunk)
        ON (n.embedding)
        OPTIONS { indexConfig: { dimensions: 3, metric: 'cosine' } }
        """
    )

    with db.exec_one(
        """
        CALL db.index.vector.queryNodes('chunkEmbedding', 10, [0.10, 0.30, 0.50])
        YIELD node, score
        RETURN node, score
        """
    ) as table:
        print(table.to_rows())

For exact query-time scoring without a native vector index, use the Neo4j-compatible scalar function vector.similarity.cosine(left, right) inside WITH, WHERE, RETURN, and ORDER BY.

For text-to-vector search, register an embedding callback and reference it from CREATE VECTOR INDEX. Velr invokes the callback for index maintenance when indexed source values change and for text queries passed to CALL db.index.vector.queryNodes(...).

OPTIONS { indexConfig: ... } configures Velr vector indexes. Prefer the Neo4j-style names where they exist; shorter aliases are accepted for existing queries and examples.

OPTIONS {
  indexConfig: {
    `vector.dimensions`: 384,
    `vector.similarity_function`: 'cosine',
    embedder: 'text',
    cache_policy: 'required',
    `vector.hnsw.ef_search`: 128
  }
}

Core options:

Option Accepted aliases Meaning
`vector.dimensions` dimensions Required vector width. Every stored vector, embedder output, and query vector must contain exactly this many values.
`vector.similarity_function` metric, similarity_function Distance function. Use cosine for most semantic embeddings, l2/euclidean for geometric distance, and dot/inner_product/max_inner_product for inner-product retrieval. Default: cosine.
embedder velr.embedder Name of a registered callback for ON EACH [...] indexes. Omit it for stored-vector indexes such as ON (n.embedding).
embedder_fingerprint embedderFingerprint, velr.embedder_fingerprint Optional model/version metadata stored with the index definition. Velr does not use it to call the embedder.
cache_policy cachePolicy Embedder-backed indexes only. required stores generated embeddings in the database so index files can be rebuilt without recomputing them; best_effort skips cache write errors; none stores no generated embedding cache. Defaults: required with embedder, none without. Stored-vector indexes require none because the vector property is already the durable source.

HNSW tuning options:

Option Integer count Meaning
`vector.hnsw.m` 1..512 neighbors Maximum graph connectivity per vector. For example, 16 means each vector keeps roughly 16 HNSW neighbor links. Higher values can improve recall on difficult datasets, with more memory, larger index files, and slower builds.
`vector.hnsw.ef_construction` 1..3200 candidates Build-time candidate pool per inserted vector. For example, 320 means the builder considers a working set of 320 candidate neighbors while placing each vector. Higher values can improve index quality and recall, usually with slower index creation.
`vector.hnsw.ef_search` 1..3200 candidates Query-time candidate pool. For example, 128 means each search keeps a working set of 128 candidate vectors while traversing the HNSW graph. Higher values can improve recall, usually with slower searches. Velr's default is 64.

Velr manages the vector scalar format and storage/cache engines internally. Use the options above for application configuration.

from velr.driver import Velr


def embed_text(text: str, dimensions: int) -> list[float]:
    # Call your embedding model here.
    return [0.0] * dimensions


def embedder(inputs):
    vectors = []
    for input in inputs:
        text = "\n".join(
            str(field.value)
            for field in input.fields
            if field.value_type == "string"
        )
        prefix = "query: " if input.purpose == "query" else "passage: "
        vectors.append(embed_text(prefix + text, input.dimensions))
    return vectors


with Velr.open("mygraph.db") as db:
    db.register_vector_embedder("text", embedder)

    db.run(
        """
        CREATE VECTOR INDEX paperEmbedding IF NOT EXISTS
        FOR (n:Paper)
        ON EACH [n.title, n.abstract]
        OPTIONS { indexConfig: { dimensions: 384, metric: 'cosine', embedder: 'text' } }
        """
    )

    with db.exec_one(
        """
        CALL db.index.vector.queryNodes('paperEmbedding', 10, 'paper about greek letters')
        YIELD node, score
        RETURN node, score
        """
    ) as table:
        with table.iter_rows() as rows:
            for row in rows:
                print([cell.as_python() for cell in row])

ON EACH [n.title, n.abstract] passes both property values to the callback in that order. Query text is passed as one unnamed string field. Vector score is metric-dependent and non-normalized; higher scores are better within a single query result set.

For file-backed databases, Velr can repair missing or corrupt vector index data from stored vector properties or from registered embedders, depending on how the index was created.


Query model

A query may produce zero or more result tables.

Velr exposes three main ways to run Cypher:

  • run() executes a query or script and drains all result tables.
  • exec() returns a stream of result tables.
  • exec_one() expects exactly one result table.

run()

Use run() when you only care about side effects:

with Velr.open(None) as db:
    db.run("CREATE (:Movie {title:'Interstellar', released:2014})")

exec_one()

Use exec_one() when the query should yield exactly one table:

with Velr.open(None) as db:
    db.run("CREATE (:Person {name:'Alice', age:30})")

    with db.exec_one("MATCH (p:Person) RETURN p.name AS name, p.age AS age") as table:
        print(table.column_names())
        print(table.collect(lambda row: [cell.as_python() for cell in row]))

exec()

Use exec() when a query or script may produce multiple result tables:

with Velr.open(None) as db:
    db.run(MOVIES_CREATE)

    with db.exec(
        "MATCH (m:Movie {title:'The Matrix'}) RETURN m.title AS title; "
        "MATCH (m:Movie {title:'Inception'}) RETURN m.released AS released"
    ) as stream:
        for table in stream.iter_tables():
            print(table.column_names())
            print(table.collect(lambda row: [cell.as_python() for cell in row]))

Bounded result previews

Pass max_result_rows when a host needs projected column names and a small row sample without rewriting the Cypher text:

from velr.driver import Velr

with Velr.open_readonly("mygraph.db") as db:
    with db.exec_one(
        "MATCH (n) RETURN labels(n) AS labels, n.name AS name ORDER BY name",
        max_result_rows=20,
    ) as table:
        columns = table.column_names()
        sample = table.collect(lambda row: [cell.as_python() for cell in row])

print(columns)
print(sample)

max_result_rows=0 preserves column metadata and makes row cursors return no rows:

with Velr.open_readonly("mygraph.db") as db:
    with db.exec_one("MATCH (n) RETURN n.name AS name", max_result_rows=0) as table:
        assert table.column_names() == ["name"]
        assert table.collect(lambda row: row) == []

The cap is enforced by Velr during result emission, not by appending or injecting Cypher LIMIT, and applies independently to each result table produced by exec(). Existing Cypher LIMIT clauses still apply, so a query with LIMIT 3 and max_result_rows=5 emits at most three rows, while LIMIT 10 with max_result_rows=5 emits at most five rows. It is not a timeout or cancellation mechanism; keep read-only validation and execution deadlines as separate host concerns.

Query parameter binding

Pass params to bind openCypher parameters out of band. Query text uses $name; parameter names in Python omit the leading $. Values are passed as Cypher values, not interpolated into query text, so a Python str is always a Cypher string value.

from velr.driver import Velr

with Velr.open(None) as db:
    db.run(
        "CREATE (:Person {name: $name, age: $age})",
        params={"name": "Alice", "age": 42},
    )

    with db.exec_one(
        "MATCH (p:Person) WHERE p.age >= $min_age RETURN p.name AS name ORDER BY name",
        max_result_rows=20,
        params={"min_age": 18},
    ) as table:
        print(table.column_names())
        print(table.collect(lambda row: [cell.as_python() for cell in row]))

Supported parameter values are None, booleans, signed 64-bit integers, finite floats, strings, lists/tuples, and dicts with string keys.


Table lifetime and ownership

Table lifetime depends on how a table was obtained.

Tables from exec()

Tables pulled from exec() are stream-scoped.

They remain valid while the producing stream remains open, and closing the stream closes any still-open tables produced by that stream.

with db.exec("MATCH (n) RETURN n") as stream:
    table = stream.next_table()
    # table is valid here

# stream is now closed, so any still-open table from it is also closed

Tables from exec_one()

Tables returned by exec_one() are parent-scoped, not stream-scoped.

  • Velr.exec_one() returns a table parented to the connection.
  • VelrTx.exec_one() returns a table parented to the transaction.

That means the returned table remains usable after exec_one() returns.

Even so, tables should still be closed when no longer needed, ideally by using them as context managers.


Rows and cells

Rows are exposed through Rows. Each yielded row is a tuple of Cell objects.

Cell.as_python() converts values to normal Python objects:

  • NULL → None
  • BOOL → bool
  • INT64 → int
  • DOUBLE → float
  • TEXT → str by default
  • JSON → str by default, or parsed Python objects with parse_json=True

Example:

with db.exec_one("MATCH (p:Person) RETURN p.name AS name, p.age AS age") as table:
    with table.iter_rows() as rows:
        for row in rows:
            print(row[0].as_python(), row[1].as_python())

For convenience and safety, TEXT and JSON payloads are copied into Python bytes as rows are read, so row contents remain valid after the next fetch.


Transactions and savepoints

Use begin_tx() to open a transaction:

from velr.driver import Velr

with Velr.open(None) as db:
    with db.begin_tx() as tx:
        tx.run("CREATE (:Movie {title:'Interstellar', released:2014})")
        tx.commit()

If a transaction context exits without commit(), it is rolled back.

After commit() or rollback(), a transaction can no longer be used.

Savepoints

Velr supports two savepoint styles:

  • savepoint() creates a scoped, handle-owned savepoint.
  • savepoint_named(name) creates a transaction-owned named savepoint.

Scoped savepoints are owned by the Python handle:

  • dropping the handle closes the savepoint
  • release() releases it
  • rollback() rolls back to it and releases it

Named savepoints are owned by the transaction:

  • dropping the returned Python handle does not remove the named savepoint
  • rollback_to(name) rolls back to that named savepoint, discards any newer named savepoints, and keeps the target named savepoint active
  • release_savepoint(name) releases a named savepoint by name; the named savepoint must be the most recent active named savepoint
  • release() or rollback() on a named savepoint handle consume that named savepoint

Active named savepoints are released automatically during commit() so that surviving changes are preserved in the committed transaction.

Example:

with Velr.open(None) as db:
    with db.begin_tx() as tx:
        tx.run("CREATE (:Temp {k:'outer'})")

        tx.savepoint_named("sp1")
        tx.run("CREATE (:Temp {k:'a'})")

        tx.savepoint_named("sp2")
        tx.run("CREATE (:Temp {k:'b'})")

        tx.rollback_to("sp1")  # undoes a and b, drops sp2, keeps sp1 active
        tx.run("CREATE (:Temp {k:'c'})")

        tx.release_savepoint("sp1")
        tx.commit()

pandas / Polars / PyArrow interop

Velr can export result tables as Arrow IPC and convert them into:

  • pyarrow.Table
  • pandas.DataFrame
  • polars.DataFrame

pandas

with Velr.open(None) as db:
    db.run(MOVIES_CREATE)

    df = db.to_pandas(
        "MATCH (m:Movie) "
        "RETURN m.title AS title, m.released AS released "
        "ORDER BY released"
    )
    print(df)

Polars

with Velr.open(None) as db:
    db.run(MOVIES_CREATE)

    df = db.to_polars(
        "MATCH (m:Movie) "
        "RETURN m.title AS title, m.released AS released "
        "ORDER BY released"
    )
    print(df)

PyArrow

with Velr.open(None) as db:
    db.run(MOVIES_CREATE)

    tbl = db.to_pyarrow(
        "MATCH (m:Movie) "
        "RETURN m.title AS title, m.released AS released "
        "ORDER BY released"
    )
    print(tbl)

Export from an existing table

with db.exec_one("MATCH (m:Movie) RETURN m.title AS title") as table:
    pa_tbl = table.to_pyarrow()
    df = table.to_pandas()
    pl_df = table.to_polars()

Use table.to_rows() for the normal Python result shape. It returns ready-to-use row lists and is the recommended path when you intend to read the whole result. Use table.iter_rows() when you want cursor-style iteration: it yields one row at a time, so you can stop early or avoid building a full Python list. As with database cursors generally, a query plan can still use temporary storage for operations such as sorting or aggregation.

to_rows() returns a list of row lists. Cypher lists and maps are decoded into Python lists and dicts. By default it returns every column projected by the query; prefer expressing the result shape in Cypher with RETURN.

Use to_records() when you want named dictionaries instead of positional row lists; it returns the same list-of-dicts shape accepted by bind_records(). Some application schemas store JSON documents in string properties. If you project one of those properties and want Python dict/list values, pass columns for those projected columns. This is explicit: ordinary Cypher strings stay strings unless you opt in.

with db.exec_one(
    """
    MATCH (d:Document)
    RETURN d.id AS id, d.metadata AS metadata
    """
) as table:
    rows = table.to_rows()
    decoded_rows = table.to_rows(columns=("metadata",))
    records = table.to_records(columns=("metadata",))

For the common case where you only need the final result table, the connection also has the same shortcut:

rows = db.to_rows("""
MATCH (d:Document)
RETURN d.id AS id, d.metadata AS metadata
""")

records = db.to_records("""
MATCH (d:Document)
RETURN d.id AS id, d.metadata AS metadata
""")

Because to_records() returns the same list-of-dicts shape accepted by bind_records(), projected results can be rebound under a logical name:

records = db.to_records("""
MATCH (d:Document)
RETURN d.id AS id, d.metadata AS metadata
""")

db.bind_records("_documents", records)

Binding Arrow, pandas, Polars, NumPy, and records

Velr can also bind external columnar data under a logical name and query it from Cypher.

Supported bind helpers include:

  • bind_arrow()
  • bind_arrow_ipc()
  • bind_pandas()
  • bind_polars()
  • bind_numpy()
  • bind_records()

bind_arrow_ipc() accepts Arrow IPC file / Feather v2 bytes and borrows the buffer only for the duration of the call.

Bind a pandas DataFrame

import pandas as pd
from velr.driver import Velr

df = pd.DataFrame(
    [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 41},
    ]
)

with Velr.open(None) as db:
    db.bind_pandas("_people", df)

    db.run("""
    UNWIND BIND('_people') AS r
    CREATE (:Person {name:r.name, age:r.age})
    """)

    out = db.to_pandas("MATCH (p:Person) RETURN p.name AS name, p.age AS age ORDER BY age")
    print(out)

Bind a list of dicts

rows = [
    {"name": "Alice", "age": 30},
    {"name": "Bob", "age": 41},
]

with Velr.open(None) as db:
    db.bind_records("_people", rows)
    db.run("""
    UNWIND BIND('_people') AS r
    CREATE (:Person {name:r.name, age:r.age})
    """)

bind_records() is available on both Velr and VelrTx. Use it when your input is naturally a list of JSON-compatible Python dictionaries: None, bools, signed 64-bit integers, finite floats, strings, lists, tuples, and dicts. It is the write-side counterpart to to_records().

Use bind_arrow() when your data is already Arrow-backed, or when an adapter intentionally wants Arrow's columnar layout for large vector/array-heavy batches. Use bind_records(..., types=...) only when you specifically want Arrow-style type control while starting from Python records.

with Velr.open(None) as db:
    with db.begin_tx() as tx:
        tx.bind_records("_people", rows)
        tx.run("""
        UNWIND BIND('_people') AS r
        CREATE (:Person {name:r.name, age:r.age})
        """)
        tx.commit()

Explain support

Velr exposes explain traces through:

  • Velr.explain()
  • Velr.explain_analyze()
  • VelrTx.explain()
  • VelrTx.explain_analyze()

These return an ExplainTrace, which can be navigated incrementally or fully materialized with snapshot().

with Velr.open(None) as db:
    with db.explain("MATCH (p:Person) RETURN p.name AS name") as xp:
        print(xp.to_compact_string())

Query language support

Velr supports the openCypher query language and passes all positive openCypher TCK tests. Exact error semantics, including error messages, categories, and timing, are not guaranteed to match other openCypher implementations.


OpenCypher functions

The following openCypher functions and constructors are available:

Graph and path

  • id()
  • type()
  • labels()
  • keys()
  • properties()
  • length()
  • nodes()
  • relationships()

Lists and predicates

  • size()
  • head()
  • last()
  • tail()
  • reverse()
  • range()
  • all()
  • any()
  • none()
  • single()

Strings and conversion

  • coalesce()
  • toInteger()
  • toString()
  • toLower()
  • trim()
  • substring()
  • split()

Numeric

  • abs()
  • ceil()
  • rand()
  • sign()
  • sqrt()

Temporal

  • date()
  • time()
  • localtime()
  • datetime()
  • localdatetime()
  • duration()
  • datetime.fromepoch()
  • datetime.fromepochmillis()
  • date.realtime(), date.transaction(), date.statement()
  • time.realtime(), time.transaction(), time.statement()
  • localtime.realtime(), localtime.transaction(), localtime.statement()
  • datetime.realtime(), datetime.transaction(), datetime.statement()
  • localdatetime.realtime(), localdatetime.transaction(), localdatetime.statement()

Aggregates

  • count()
  • sum()
  • avg()
  • min()
  • max()
  • collect()
  • percentileDisc()
  • percentileCont()

Thread safety

Velr connections and active result handles are not safe for concurrent use from multiple threads.

If you need parallelism:

  • open one connection per thread
  • do not share active connections
  • do not share transactions, streams, tables, row iterators, or explain traces across threads

Platform support

Supported distributions may include prebuilt binary wheels for common platforms. Where binary wheels are available, Velr is ready to use after installation.

Currently bundled targets:

* macOS (arm64)
* Linux x86_64
* Linux aarch64
* Windows x86_64

Building wheels

Each Python platform workflow runs cargo run --locked -p xtask -- bundle-host once to build its native runtime, then uploads that binary as a workflow artifact. The Python 3.12, 3.13, and 3.14 wheel jobs download and package the same artifact, selected with VELR_NATIVE_LIBRARY. This produces four native builds and twelve independently tested wheels. The existing Rust release workflows are unchanged, and Python jobs do not require Docker.

Before native compilation, the workflows capture the source version with scripts/resolve_python_wheel_version.py and export it through SETUPTOOLS_SCM_PRETEND_VERSION_FOR_VELR. The native job also passes this version to its wheel jobs, so rebuilding tracked runtime binaries preserves the release version. A tag build must match the source version before compilation; branch builds retain their development versions.

The host bundler uses the Rust native release build flags and target triples. On macOS it also applies the deployment target and stripping procedure used by bundle-macos. Linux x86_64 wheels build on Ubuntu 22.04, matching the Rust native release runner. Auditwheel checks compatibility against the build host's glibc version; the resulting wheel tags describe the verified minimum version.

For example, to build a macOS ARM64 wheel locally:

cargo run --locked -p xtask -- bundle-host
VELR_NATIVE_LIBRARY="$PWD/rust/velr-rust-driver/runtime/macos-aarch64/prebuilt/libvelrc.dylib" PYTHON=python3 \
  bash scripts/build_wheel_osx_linux.sh

For Linux, select linux-x86_64/prebuilt/libvelrc.so or linux-aarch64/prebuilt/libvelrc.so under the same runtime directory. On Windows:

cargo run --locked -p xtask -- bundle-host
$env:VELR_NATIVE_LIBRARY = "$PWD/rust/velr-rust-driver/runtime/windows-x86_64/prebuilt/velrc.dll"
./scripts/build_wheel_windows_amd64.ps1

Both scripts run the host recovery checks, the Python tests against an editable install, and the tests against the resulting wheel in a fresh environment.


License

See LICENSE and LICENSE.runtime for the full license texts.

Metadata

Release files for velr 0.2.54

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for velr 0.2.54
File
velr-0.2.54-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
velr-0.2.54-cp314-cp314-manylinux_2_39_aarch64.whl CPython 3.14 CPython 3.14 Linux glibc 2.39+ ARM64 Details
velr-0.2.54-cp314-cp314-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.34+ x86-64, Linux glibc 2.35+ x86-64 Details
velr-0.2.54-cp314-cp314-macosx_11_0_universal2.whl CPython 3.14 CPython 3.14 macOS 11.0+ universal2 (ARM64, x86-64) Details
velr-0.2.54-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
velr-0.2.54-cp313-cp313-manylinux_2_39_aarch64.whl CPython 3.13 CPython 3.13 Linux glibc 2.39+ ARM64 Details
velr-0.2.54-cp313-cp313-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.34+ x86-64, Linux glibc 2.35+ x86-64 Details
velr-0.2.54-cp313-cp313-macosx_11_0_universal2.whl CPython 3.13 CPython 3.13 macOS 11.0+ universal2 (ARM64, x86-64) Details
velr-0.2.54-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
velr-0.2.54-cp312-cp312-manylinux_2_39_aarch64.whl CPython 3.12 CPython 3.12 Linux glibc 2.39+ ARM64 Details
velr-0.2.54-cp312-cp312-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.34+ x86-64, Linux glibc 2.35+ x86-64 Details
velr-0.2.54-cp312-cp312-macosx_11_0_universal2.whl CPython 3.12 CPython 3.12 macOS 11.0+ universal2 (ARM64, x86-64) Details

Total release size: 96.4 MB

Release files / velr-0.2.54-cp314-cp314-win_amd64.whl

Download URL velr-0.2.54-cp314-cp314-win_amd64.whl
Size 8.0 MB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
3b7466f7d1ba9699c50dba1ad592bc444c3cdcabce96b399a44af1308c4b8b2b
BLAKE2b-256 checksum
How to use checksums
9ca19e411d7e32abad3f9f89e972f6b4d102d9be8e23491a86a65db7e4de9d80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp314-cp314-manylinux_2_39_aarch64.whl

Download URL velr-0.2.54-cp314-cp314-manylinux_2_39_aarch64.whl
Size 8.9 MB
Tags CPython 3.14 Linux glibc 2.39+ ARM64
SHA-256 checksum
How to use checksums
1c77a2e82fd6e1a3421c5d4a29bc0ad1d849ebd576b46382589d11a43a06fa0d
BLAKE2b-256 checksum
How to use checksums
5f743113d458156ac1fd023bdc1645424b51e9b266657a2099a219d103d7e94f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp314-cp314-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl

Download URL velr-0.2.54-cp314-cp314-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl
Size 8.8 MB
Tags CPython 3.14 Linux glibc 2.34+ x86-64 Linux glibc 2.35+ x86-64
SHA-256 checksum
How to use checksums
0d33184203169dc7b82a0db6362977cb6a1d57757784bdcb3d328e34fa8bb724
BLAKE2b-256 checksum
How to use checksums
1b7c1c868b65a9cb6c60d67fee75d44a796c22fdb9ef566f53947ddd5833ee8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp314-cp314-macosx_11_0_universal2.whl

Download URL velr-0.2.54-cp314-cp314-macosx_11_0_universal2.whl
Size 6.6 MB
Tags CPython 3.14 macOS 11.0+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
94af960bef86f184763ba68d569f6b0b2a27d8f50d04e26b6f1b9e7891dfff50
BLAKE2b-256 checksum
How to use checksums
1ba1682960bb4da3b177da73fbf87bdcac86a0c26106086216a9e9e059075793
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp313-cp313-win_amd64.whl

Download URL velr-0.2.54-cp313-cp313-win_amd64.whl
Size 7.7 MB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
f67f25c35cbe46d0d041d8169eb7341e60e23ddf550f09e013999f75314be66e
BLAKE2b-256 checksum
How to use checksums
a27327ab0765677a87dfbcc2f2566feb8e58cdd0147ea2a9edb03dc8539956df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp313-cp313-manylinux_2_39_aarch64.whl

Download URL velr-0.2.54-cp313-cp313-manylinux_2_39_aarch64.whl
Size 8.9 MB
Tags CPython 3.13 Linux glibc 2.39+ ARM64
SHA-256 checksum
How to use checksums
fff298bce8b5389c1595d589a84af6c5f494027ab65187b80004873bd7a2437d
BLAKE2b-256 checksum
How to use checksums
f238c86e288d92af765ba27c1c9235e4bf95c977107781e55cd3d13d7ccea2a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp313-cp313-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl

Download URL velr-0.2.54-cp313-cp313-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl
Size 8.8 MB
Tags CPython 3.13 Linux glibc 2.34+ x86-64 Linux glibc 2.35+ x86-64
SHA-256 checksum
How to use checksums
3ec5306087212f33029e032a15ab488bcaa75900166f977540aee4f18a75d08c
BLAKE2b-256 checksum
How to use checksums
eea23cbf2bd1e8bfe9fef1e8c350eeddff49e8b82c45528c9f5e0c5699edb597
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp313-cp313-macosx_11_0_universal2.whl

Download URL velr-0.2.54-cp313-cp313-macosx_11_0_universal2.whl
Size 6.6 MB
Tags CPython 3.13 macOS 11.0+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
cdebb438b81847176b8ea5953a3e4ee1dbf59afb6aa47be7521270460149cf82
BLAKE2b-256 checksum
How to use checksums
65ac07a2dffefefa27243cb11c0d673ed8cd0fd0854d7808ae021a19968e0c72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp312-cp312-win_amd64.whl

Download URL velr-0.2.54-cp312-cp312-win_amd64.whl
Size 7.7 MB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
7a7a665a5aa1d89ebcc0a5019ee42f0da705b8c47e470e65a7c85da2a52885f4
BLAKE2b-256 checksum
How to use checksums
a045bf893b0361930879cb0e7f70e1e54557f30617eade0052bd182397c3bbc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp312-cp312-manylinux_2_39_aarch64.whl

Download URL velr-0.2.54-cp312-cp312-manylinux_2_39_aarch64.whl
Size 8.9 MB
Tags CPython 3.12 Linux glibc 2.39+ ARM64
SHA-256 checksum
How to use checksums
ca8afda395b8976748920f3b6c3f52dbdc5b6e0df42a8ad6956b1457275f30b9
BLAKE2b-256 checksum
How to use checksums
d0c887f673de829cc4739d5a5bcc5bdc520eda68db851dda4fbadd89e628c031
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp312-cp312-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl

Download URL velr-0.2.54-cp312-cp312-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl
Size 8.8 MB
Tags CPython 3.12 Linux glibc 2.34+ x86-64 Linux glibc 2.35+ x86-64
SHA-256 checksum
How to use checksums
1362cadf66db599a9217aff5c731b65104d1985b7435aa5f5cf7bc1e1df5ec0d
BLAKE2b-256 checksum
How to use checksums
2c68f59e25babfa9a141a1f33d43e160b6e776908d378e52235bc6fa2a410ee8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / velr-0.2.54-cp312-cp312-macosx_11_0_universal2.whl

Download URL velr-0.2.54-cp312-cp312-macosx_11_0_universal2.whl
Size 6.6 MB
Tags CPython 3.12 macOS 11.0+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
c3816299f9d5f1c3e825ba5b0c8f988acdb46ba1bc2b10c14bb6a943b5ccc29f
BLAKE2b-256 checksum
How to use checksums
c98e660c500d3f3afecf38543d07af39935db6be49aa43bc5f94f9713f6aa6da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for velr 0.2.54

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 12 files in this release have been uploaded with provenance metadata.

Select from 12 files

Attestation for velr-0.2.54-cp314-cp314-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.54 This release

12 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page