GFFBase

A genomic-annotation engine built for whole-genome scale: a Rust GFF3/GTF parser, DuckDB columnar storage, and a zero-copy PyArrow interface — with the gffutils API preserved, so most code migrates by changing one import.

GFFBase reads GFF3 and GTF at whole-genome scale and answers the questions a genomics pipeline actually asks — spatial queries over intervals, hierarchy walks from gene to transcript to exon, and bulk extraction into Arrow, pandas or polars without a Python loop in the middle. The storage engine is DuckDB, so a database is one portable file and every query is columnar.

PyPI Python versions License

What you can do with GFFBase

🧬 Query intervals at genome scale

Ask for a region and get the features that overlap it, from an R-tree index built during ingest.

3. Spatial queries
🌳 Walk the annotation hierarchy

children, parents and the batched forms, backed by a transitive closure so depth costs nothing at query time.

2. Standard relational queries
🔄 Migrate from gffutils

The legacy API is preserved surface-for-surface. Most scripts move by changing one import.

Migrating from gffutils to gffbase
⚡ Extract in bulk, without a Python loop

children_batched(format="arrow") returns one Arrow table for thousands of anchors.

5. Vectorized ML API — the ones that make GFFBase fast
📊 Read the measured numbers

Head-to-head benchmarks on the canonical human annotations, with the machine, versions and commit of each run recorded.

Performance
🧰 Work from the command line

Build, inspect, validate and migrate a database without writing Python.

Command line

Measured performance

Every figure below is generated from the committed benchmark artifact, never typed in. See Performance for the full sweep and Benchmark methodology for how it was run.

Read the ingest column as a draw. gffbase spans 1.21× to 0.69× against gffutils: ahead where per-feature overhead dominates, behind on the attribute-dense whole-genome files. Both engines are attribute-bound and effectively serial. The durable advantages — batched extraction, spatial indexing, SQL over the whole corpus — are elsewhere. peak RSS is ingest plus exhaustive validation, not what the default path costs.

Corpus

Format

Lines

gffbase ingest

legacy ingest

speedup

peak RSS (ingest + full validation)

spatial qps

batched (5 k anchors)

GENCODE v49 (basic)

GTF

6,068,892

10 min 14 s

7 min 1 s

0.69×

53.57 GB

707 ±0% (n=5)

963 ms / 1.93 M desc

GENCODE v49 (basic)

GFF3

6,066,054

11 min 8 s

9 min 59 s

0.90×

62.00 GB

705 ±0% (n=5)

1096 ms / 1.93 M desc

RefSeq GRCh38.p14

GFF3

4,932,571

7 min 2 s

6 min 34 s

0.93×

26.80 GB

540 ±0% (n=5)

588 ms / 999 k desc

CHESS 3.1.3

GFF3

2,761,061

1 min 53 s

2 min 17 s

1.21×

3.38 GB

702 ±0% (n=5)

202 ms / 161 k desc

MANE v1.5 (Ensembl)

GFF3

524,834

40.0 s

45.7 s

1.14×

3.98 GB

840 ±0% (n=5)

206 ms / 156 k desc


Install

pip install gffbase

Note

This site documents gffbase 0.2.0, released 2026-09-11. Upgrading from 0.1.0 fixes two SQL injection vulnerabilities; see the security advisory.

Quick start

from gffbase import create_db

with create_db("gencode.v49.annotation.gtf.gz", "gencode.duckdb") as db:
    for tx in db.children("ENSG00000139618", featuretype="transcript"):
        print(tx.id, tx.start, tx.end)

    for feature in db.region("chr17:43044295-43125483", featuretype="exon"):
        print(feature)

See Installation for the supported platforms, and Quickstart for a worked example that runs end to end.