Apache DataFusion Ballista Distributed Query Engine https://datafusion.apache.org/ballista
  • Rust 86.3%
  • Python 11.5%
  • Shell 1.2%
  • Jupyter Notebook 0.5%
  • Dockerfile 0.4%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Marko Milenković b497530ff7
feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754)
* add python client

* fix race in _pipelined

* dev/update_datafusion_proto.py now regenerates
the Python gRPC stubs every time it updates the
vendored protos

* add a test showing that a SET ballista.* on
the session actually reaches the scheduler
2026-11-05 22:04:15 +00:00
.devcontainer
.github feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754) 2026-11-05 22:04:15 +00:00
ballista feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754) 2026-11-05 22:04:15 +00:00
ballista-cli feat: finish scheduler jobs on shutdown and unify signal handling (#2631) 2026-10-26 20:02:02 +00:00
benchmarks remove unused sys making ruff to fail (#2769) 2026-11-03 22:39:40 +00:00
chaos-testing fix(chaos): never hand two processes of one cluster the same port (#2740) 2026-11-03 10:19:58 +00:00
ci/scripts ci: fix lint scripts that skipped checks or passed without running (#2473) 2026-09-23 16:24:26 -06:00
dev feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754) 2026-11-05 22:04:15 +00:00
docs feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754) 2026-11-05 22:04:15 +00:00
examples feat: add a Python ADBC example and TPC-H runner for Flight SQL (#2496) 2026-10-25 15:01:24 -06:00
python feat(python): Add Python gRPC client with BallistaPythonSessionContext (#2754) 2026-11-05 22:04:15 +00:00
.asf.yaml ci: add a merge queue and move the TPC-H and TPC-DS suites behind it (#2653) 2026-10-26 12:12:56 -06:00
.dockerignore feat: decoupled result service for serving query results (#2577) 2026-10-14 10:40:33 -07:00
.gitignore chore: remove leftovers inherited from Arrow (#2474) 2026-09-25 09:13:40 +01:00
Cargo.lock chore(deps): bump tonic-prost from 0.14.7 to 0.14.9 (#2733) 2026-11-03 10:33:38 +00:00
Cargo.toml chore(deps): bump rstest from 0.27.0 to 0.28.0 (#2640) 2026-10-22 08:21:01 +01:00
CHANGELOG.md
clippy.toml
CODE_OF_CONDUCT.md
CONTRIBUTING.md chore: remove leftovers inherited from Arrow (#2474) 2026-09-25 09:13:40 +01:00
docker-compose.yml feat: finish scheduler jobs on shutdown and unify signal handling (#2631) 2026-10-26 20:02:02 +00:00
header
LICENSE.txt chore: prune stale NOTICE.txt entries, add mini-redis attribution (#2300) 2026-08-16 08:50:34 +01:00
NOTICE.txt chore: prune stale NOTICE.txt entries, add mini-redis attribution (#2300) 2026-08-16 08:50:34 +01:00
pre-commit.sh ci: fix lint scripts that skipped checks or passed without running (#2473) 2026-09-23 16:24:26 -06:00
README.md add execution modes to readme (#2744) 2026-11-02 19:46:37 +00:00
ROADMAP.md
ruff.toml ci: run ruff over the whole repository (#2472) 2026-09-26 15:11:01 -06:00
rust-toolchain.toml
rustfmt.toml
taplo.toml

Ballista: Making DataFusion Applications Distributed

Apache licensed

logo

Ballista is a distributed query execution engine that enhances Apache DataFusion by enabling the parallelized execution of workloads across multiple nodes in a distributed environment.

Existing DataFusion application:

use datafusion::prelude::*;

#[tokio::main]
async fn main() -> datafusion::error::Result<()> {
    let ctx = SessionContext::new();

    // register the table
    ctx.register_csv("example", "tests/data/example.csv", CsvReadOptions::new())
        .await?;

    // create a plan to run a SQL query
    let df = ctx
        .sql("SELECT a, MIN(b) FROM example WHERE a <= b GROUP BY a LIMIT 100")
        .await?;

    // execute and print results
    df.show().await?;
    Ok(())
}

can be distributed with few lines of code changed:

Important

There is a gap between DataFusion and Ballista, which may bring incompatibilities. The community is actively working to close the gap

use ballista::prelude::*;
use datafusion::prelude::*;

#[tokio::main]
async fn main() -> datafusion::error::Result<()> {
    // create SessionContext with ballista support
    // standalone context will start all required
    // ballista infrastructure in the background as well
    let ctx = SessionContext::standalone().await?;

    // everything else remains the same

    // register the table
    ctx.register_csv("example", "tests/data/example.csv", CsvReadOptions::new())
        .await?;

    // create a plan to run a SQL query
    let df = ctx
        .sql("SELECT a, MIN(b) FROM example WHERE a <= b GROUP BY a LIMIT 100")
        .await?;

    // execute and print results
    df.show().await?;
    Ok(())
}

For documentation or more examples, please refer to the Ballista User Guide.

Who is Ballista for

Ballista serves several distinct audiences:

  • DataFusion users going multi-node — you already use Apache DataFusion on a single machine and have outgrown it. Ballista runs the same SQL and DataFrame workloads across a cluster with minimal code changes and the same results.
  • Spark users wanting the same execution model — you run Spark SQL or batch jobs and want a lighter, Rust-native alternative without relearning a new paradigm. Ballista keeps the familiar model: plans split into stages at shuffle boundaries, tasks over partitions, executors with vcores, and adaptive query execution (AQE).
  • Library users building a specialized engine — you are building a bespoke distributed query engine and want reusable scheduler, executor, and plan-serialization building blocks with extension points, instead of writing distributed execution from scratch.

These audiences are documented in more detail, along with the guarantees each relies on, in the User Personas guide.

Architecture

A Ballista cluster consists of one or more scheduler processes and one or more executor processes. These processes can be run as native binaries and are also available as Docker Images, which can be easily deployed with Docker Compose or Kubernetes.

The following diagram shows the interaction between clients and the scheduler for submitting jobs, and the interaction between the executor(s) and the scheduler for fetching tasks and reporting task status.

Ballista Cluster Diagram

See the architecture guide for more details.

Execution Modes

Ballista supports two execution modes, selected with ballista.execution.mode. Staged execution, the default, runs a job one stage at a time, the way Apache Spark does: each stage writes its output to shuffle files, and a failed task is simply re-run from them, which suits long-running jobs and busy shared clusters.

Pipelined execution (experimental) runs a job the way Trino does: every task is scheduled at once and stages stream record batches to each other over Arrow Flight, with no intermediate data written to disk, so results reach the client sooner, at the cost of a failed task failing the whole job. It suits short, latency-sensitive queries on clusters with room for the whole job. See the Pipelined Execution Guide for details.

Getting Started

The easiest way to get started is to run one of the standalone or distributed examples. After that, refer to the Getting Started Guide.

Web Terminal User Interface (Web TUI)

Ballista provides a browser-based Web TUI for monitoring a running cluster. It exposes the TUI views for jobs, executors, metrics, and scheduler information directly in a web browser.

Ballista Web TUI

When the scheduler HTTP endpoint is available, opening the scheduler address in a browser, for example http://localhost:50050, redirects to a hosted Web TUI.

For more information, including how to run the Web TUI locally, see the Ballista CLI documentation.

Cargo Features

Ballista uses Cargo features to enable optional functionality. Below are the available features for each crate.

ballista (client)

Feature Default Description
standalone Yes Enables standalone mode with in-process scheduler and executor

ballista-core

Feature Default Description
arrow-ipc-optimizations Yes Enables Arrow IPC optimizations for better shuffle performance
build-binary No Required for building binary executables (AWS S3 support, CLI parsing)
force_hash_collisions No Testing-only: forces all values to hash to same value
utoipa No Derives OpenAPI schemas for scheduler REST types; enabled by ballista-scheduler's rest-api

ballista-scheduler

Feature Default Description
build-binary Yes Builds the scheduler binary with CLI and logging
substrait No Enables Substrait plan support
prometheus-metrics No Enables Prometheus metrics collection
graphviz-support No Enables execution graph visualization
keda-scaler No Kubernetes Event Driven Autoscaling integration
rest-api Yes Enables REST API endpoints, the OpenAPI spec, and the history server
disable-stage-plan-cache No Disables caching of stage execution plans

ballista-executor

Feature Default Description
arrow-ipc-optimizations Yes Enables Arrow IPC optimizations
build-binary Yes Builds the executor binary with CLI and logging
mimalloc Yes Uses mimalloc memory allocator for better performance

ballista-cli

Feature Default Description
cli Yes Builds the ballista-cli SQL shell binary
tui Yes Enables a REST client with Terminal User Interface
web No Builds the WebAssembly Web TUI (see the Ballista CLI documentation)

TUI Jobs table

Usage Examples

# Build with standalone support (default)
cargo build -p ballista

# Build with Substrait support
cargo build -p ballista-scheduler --features substrait

Project Status

Ballista supports a wide range of SQL, including CTEs, Joins, and subqueries and can execute complex queries at scale, but still there is a gap between DataFusion and Ballista which we want to bridge in near future.

Refer to the DataFusion SQL Reference for more information on supported SQL.

Contribution Guide

Please see the Contribution Guide for information about contributing to Ballista.