Introducing pg_bio: The PostgreSQL Bioinformatics Operating System

Biological data is fundamentally incompatible with traditional database architectures.

When you sequence a genome, fold a protein in 3D space, or generate a high-dimensional AI vector using models like Meta’s ESM-2, the resulting data is a nightmare to query. Modern bioinformatics usually relies on dumping thousands of flat text files (like .pdb or .fasta) onto a hard drive, then writing slow Python scripts using Pandas and Numpy to crunch the math in a massive for loop.

Today, we are changing that. We are releasing pg_bio: a hyper-optimized PostgreSQL extension written entirely in Rust. It pushes the heaviest biological mathematics deep into the database engine, transforming Postgres into a natively AI-aware bioreactor.


The Four Architectural Bottlenecks of Computational Biology

Before we dive into the hands-on tutorial, it is crucial to understand the four architectural bottlenecks pg_bio was built to solve.

1. The 3D Spatial Bottleneck (The Math Problem)

Calculating 3D distances between atoms is traditionally an $O(N^2)$ brute force nightmare. We solved this by creating a custom ResidueCoord type that weaves $X, Y, Z$ floats into a Morton Code (Z-Order Curve).

graph TD A[3D Atomic Coordinate] -->|X 10.5, Y 12.0, Z 8.1| B{Bit Interleaving} B -->|Morton Code Generation| C(1D Integer 491029348) C --> D[Standard PostgreSQL B-Tree Index]

This compresses 3D space into a 1D line, allowing standard B-Trees to index 3D protein structures.

2. The AI Vector Bottleneck (The I/O Problem)

Fetching massive floating-point arrays (AI Embeddings) out of the database to run cosine math in Python clogs the TCP network.

sequenceDiagram participant Python participant Network participant Postgres Python->>Network: SELECT embedding FROM proteins Network->>Postgres: Request Data Postgres-->>Network: Transmitting 20,400 Arrays (I/O BOTTLENECK) Network-->>Python: Receives Megabytes of Floats Note over Python: Runs scipy cosine distance Note over Python: Sorts and finds Top 5

pg_bio solves this by executing embedding_cosine_distance(REAL[], REAL[]) natively in Rust C-memory, bypassing the network entirely.

3. The Genomic Looping & Energetic Network Bottleneck (The CSR Attention Problem)

Deep learning models (like the Zhou Lab ORCA model or ESMFold $N \times N$ attention matrices) and per-residue MD free-energy decompositions output massive matrices to track which residues or chromosome loci physically interact. pg_bio compresses these into a SparseAttentionMap (Compressed Sparse Row) type natively.

graph LR A[ORCA Hi-C / MM-PBSA Output] -->|Compress to CSR| B(SparseAttentionMap) B -->|Stored Natively in pg_bio| C[(Postgres)] C -->|SQL Query| D[Find Promoter Loops & Cryptic Hotspots]

4. The Cheminformatics Graph Normalization Bottleneck (The Kekulé vs. Aromatic Trap)

If you hand a naive SMILES parser and Weisfeiler-Lehman (WL) hasher to a computational chemist, it will break on their very first query. Why? Because a chemist will insert Benzene into your database using the Kekulé form (C1=CC=CC=C1 — uppercase carbons with alternating single and double bonds) or insert a drug as a ChEMBL sodium salt ([Na+].O=C([O-])C1=CC=CC=C1), and then immediately query for it using the aromatic form (c1ccccc1 or O=C(O)c1ccccc1).

Without an Aromaticity Perception & Salt/Tautomer Normalization pass between the SMILES lexer and the WL hasher, the database sees C=C-C in row 1 and c:c:c in the query, produces two completely different 64-bit hashes, and returns zero matches.

In systems engineering terms, aromaticity perception is simply Unicode NFC/NFD normalization for cyclic graphs governed by Hückel’s $4n + 2$ rule:

  1. Every atom in a candidate cycle must be part of a conjugated $sp^2$ system.
  2. The total number of $\pi$-electrons around the cycle must equal $4n + 2$ ($6, 10, 14, 18\dots$), which in pure integer arithmetic is a bitwise modulo check: (pi_sum >= 6) && ((pi_sum - 2) & 3) == 0.
Ring Atom State Chemical Examples $\pi$-Electrons Contributed
Has an in-ring = or : bond (or already lowercase $sp^2$ c/n) C, N, c, n in Benzene (C1=CC=CC=C1) or Pyridine (c1ccncc1) 1
Single-bonded heteroatom with a lone pair (or carbanion [C-]) [nH] in Pyrrole (C1=CC=CN1), O in Furan (c1ccoc1), S in Thiophene, [cH-]1cccc1 2
Ring Carbon with an exocyclic =O / =N / =S double bond (or [C+]) Carbonyl carbon C(=O) inside 2-Pyridone (O=C1C=CC=CN1), Caffeine, or Uracil 0 (outside oxygen steals the $\pi$-e)
Saturated $sp^3$ atom (4 single bonds, -CH2-) or triple bond # Cyclohexane (C1CCCCC1), Cyclopentadiene (C1=CC=CC1) ABORT (-1) (Breaks conjugation)
flowchart LR S["Raw SMILES\nO=C([O-])C1=CC=CC=C1.[Na+]"] --> L["1. DFS Lexer &\nRing Closures"] L --> N["2. Salt Strip (.) &\n1,3-Tautomer Norm"] N --> H["3. Hückel 4n+2\nCycle Perception"] H --> W["4. WL 64-Bit Hash +\n1024-Bit ECFP4 + VF2 (@>)"]

Once pg_bio runs this normalization pass immediately after lexing, C1=CC=CC=C1 and c1ccccc1 compile down to the exact same Molecule struct, the exact same 64-bit wl_hash, and the exact same 1024-bit ECFP4 fingerprint!


🧪 Hands-On Tutorial: Advanced Data Mining with pg_bio

With the theory out of the way, let’s look at how you can use pg_bio in the real world to mine biological datasets natively in SQL.

Imagine you have just loaded the entire UniProt Human Proteome and 200,000 synthetic atoms into your database. Here are three powerful mining scenarios.

Scenario A: Mining for Drug Binding Pockets (Spatial Z-Order)

The Goal: Find all atoms that are physically trapped inside a tiny $5 \times 5 \times 5$ Ångstrom cubic pocket in 3D space.

Instead of doing Euclidean math on all 200,000 atoms, we use the Z-Order B-Tree:

EXPLAIN ANALYZE 
SELECT atom_id, (coord).name FROM protein_atoms
WHERE z_index BETWEEN residue_z_index(create_residue_coord(10, 10, 10, '')) 
                  AND residue_z_index(create_residue_coord(15, 15, 15, ''));

The Result: The query takes exactly 7 milliseconds. Because the B-Tree jumps directly to the physical 3D sector, no math is performed during the lookup. You can instantly mine massive protein structures for active sites.

Scenario B: Off-Target Drug Prediction (AI Vector Search & Cosine Math)

The Goal: In pharmacology, if a drug binds to Protein A, it might accidentally bind to Protein B if their 3D structures are identical (causing severe side effects). How do we find identical proteins?

We represent them as 320-dimensional mathematical vectors ($A$ and $B$). pg_bio then calculates the Cosine Distance using the formula: \(\text{Distance} = 1 - \frac{A \cdot B}{\|A\| \|B\|}\) A distance close to 0.0 means they fold and function identically! But for this tutorial, let’s mine for the opposite. What if we want to find proteins that are functionally the exact opposite of Hemoglobin? We just reverse the sort to DESC:

WITH target_protein AS (
    SELECT uniprot_id, embedding FROM proteins 
    WHERE name ILIKE '%Hemoglobin%' 
    LIMIT 1
)
SELECT 
    p.uniprot_id, 
    substring(p.name from 1 for 40) as protein_name, 
    embedding_cosine_distance(p.embedding, t.embedding) as vector_distance
FROM proteins p, target_protein t
WHERE p.uniprot_id != t.uniprot_id  
  AND p.embedding IS NOT NULL       
ORDER BY vector_distance DESC  -- Note the DESC! (Highest distance = most dissimilar)
LIMIT 3;

The Result: The AI returns structural proteins like Collagen (triple helixes) and Transmembrane Pumps. It perfectly understands that a massive structural fiber is the mathematical opposite of a tiny, soluble oxygen-carrier! By leveraging ORDER BY vector_distance, you can mine the proteome for functional outliers without doing any text matching.

Scenario C: Mining for Genomic Enhancer Hubs (Sparse Attention)

The Goal: In complex genomes, “Enhancers” are DNA regions that loop in 3D space to touch multiple different genes simultaneously to turn them on.

Using the SparseAttentionMap ingested from the ORCA AI model, we can write a SQL query to mine for these topological hubs:

SELECT 
    sequence_name as synthetic_construct,
    get_top_interacting_residues(orca_hic_map, 25, 5) as top_5_dna_contacts
FROM genomic_predictions;

(Output: {1300, 1301, 500, 501, 20})

The Result: In a single line of SQL, we proved that base pairs 1300 and 500 physically loop backward in 3D space to touch the promoter at base pair 25. You can join this output against an annotations table to instantly map the entire 3D regulatory network of a cell!

Scenario D: Virtual Screening Across Kekulé, Aromatic & Salted Ligands (WL Hash + VF2 @> + Hardware Popcount %)

The Goal: In our Swarm Discovery pipeline, orphan enzymes (such as plastic-degrading Cutinases, lignin-oxidizing Peroxidases, and organohalide Dehalogenases) are paired against cognate small-molecule substrates. What happens when our database ingests MHET (the monomer of PET plastic) as a Kekulé sodium salt (O=C(OCCO)C1=CC=C(C(=O)[O-])C=C1.[Na+]), or Aspirin in Kekulé form (CC(=O)OC1=CC=CC=C1C(=O)O), and a scientist queries the database using standard aromatic SMILES (O=C(OCCO)c1ccc(C(=O)O)cc1 or c1ccccc1)?

With pg_bio’s Hückel $4n+2$ normalization pass, Weisfeiler-Lehman 64-bit canonical hashing (molecule_wl_hash), hardware-popcount 1024-bit ECFP4 Tanimoto operator (%), and backtracking VF2 Subgraph Isomorphism recheck (@>), we can screen across Kekulé, aromatic, salted, and tautomeric representations in a single SQL query:

-- 1. Prove Kekulé == Aromatic == Salted equivalence and VF2 Subgraph Isomorphism (@>)
SELECT
    molecule_wl_hash('C1=CC=CC=C1') AS kekule_hash,
    molecule_wl_hash('c1ccccc1')    AS aromatic_hash,
    molecules_are_identical('C1=CC=CC=C1', 'c1ccccc1') AS benzene_eq,
    parse_smiles('CC(=O)OC1=CC=CC=C1C(=O)O') @> parse_smiles('c1ccccc1') AS aspirin_has_benzene,
    parse_smiles('C1=CC=CC=C1') % parse_smiles('c1ccccc1') AS benzene_tanimoto,
    molecules_are_identical('CC(=O)[O-].[Na+]', 'CC(=O)O') AS salt_stripped;
kekule_hash aromatic_hash benzene_eq aspirin_has_benzene benzene_tanimoto salt_stripped
466190659499846863 466190659499846863 t t 1.0 t
-- 2. Screen Swarm Discovery enzyme families for terephthalate-containing substrates (@>)
--    and rank by 1024-bit hardware-popcount ECFP4 Tanimoto similarity (%) to aromatic MHET:
WITH q AS (
    SELECT parse_smiles('O=C(OCCO)c1ccc(C(=O)O)cc1') AS mhet_arom,
           molecule_wl_hash('O=C(OCCO)c1ccc(C(=O)O)cc1') AS mhet_hash
)
SELECT s.family_name,
       s.substrate_name,
       (s.wl_hash = q.mhet_hash) AS exact_wl_match,
       (s.mol @> parse_smiles('c1ccc(C(=O)O)cc1')) AS has_terephthalate_warhead,
       ROUND((s.mol % q.mhet_arom)::numeric, 4) AS ecfp4_tanimoto
FROM swarm_enzyme_substrates s, q
WHERE s.mol @> parse_smiles('c1ccccc1')
ORDER BY exact_wl_match DESC, ecfp4_tanimoto DESC
LIMIT 4;

14-System Chemical Equivalence Validation (0% $\rightarrow$ 100% Recall)

When we benchmarked 14 classic chemical traps—spanning $6\pi$ rings (Benzene, Pyridine), lone-pair heterocycles (Pyrrole [nH], Furan O, Thiophene S, Imidazole), exocyclic carbonyls (2-Pyridone O=C1C=CC=CN1), carbanions ([CH-]1C=CC=C1), $10\pi$ fused rings (Naphthalene, Caffeine), organic salts ([Na+].O=C([O-])C1=CC=CC=C1, [NH3+]CC(=O)O.[Cl-]), and 1,3-prototropic tautomers (CC(=N)O $\rightarrow$ CC(=O)N)—unnormalized SMILES hashing achieved 0 / 14 (0.0%) recall, while pg_bio achieved 14 / 14 (100.0%) recall across both canonical WL hashes and VF2 @> substructure checks.

10,000-Molecule Benchmark in PostgreSQL 18

Operation on 10,000 Molecules (bio_demo) Execution Time Matches Speedup vs. Python Pull
B-Tree Canonical WL Hash Lookup (wl_hash = molecule_wl_hash('O=C(O)c1ccccc1OC(=O)C') on Kekulé/Salted DB) 0.673 ms 1,000 1,513.7x
Native Rust 1024-Bit Popcount Tanimoto Scan (mol % parse_smiles(...) >= 0.85) 434.46 ms 1,000 2.3x
Native Rust VF2 Subgraph Isomorphism Scan (mol @> parse_smiles('c1ccccc1C(=O)O')) 437.85 ms 2,000 2.3x
Python Client-Side Fetch + Graph Deserialization Baseline 1,018.64 ms 1,000 1.0x

Expanding the Stack: From Active-Site Theozymes to Wet-Lab Plasmids

Since our initial release, pg_bio has grown into a 12-layer multiomics engine inside PostgreSQL:

  • Layer 8 (De Novo Enzyme Design & Theozyme Geometry): Rotationally invariant 3D Kabsch quaternion superposition (theozyme_rmsd, kabsch_rmsd), explicit $\text{Zn}^{2+}$/water coordination shell checks (has_coordinated_water_shell), Bürgi–Dunitz attack angles (bio_angle), and MD ensemble preorganization histograms (PreorganizationProfile).
  • Layer 9 (MM/GBSA & MM/PBSA Thermodynamic Auditing): Double-entry free-energy decomposition auditors (audit_mmpbsa_decomposition, solvent_shift_penalty) and CSR cryptic allosteric hotspot discovery (discover_cryptic_hotspots — see our 500 ns 5-LOX Triterpenoid MD Audit post).
  • Layer 12 (Wet-Lab Synthetic Biology & Digital Twins): Multi-host reverse translation and expression cassette design (bio_design_expression_cassette across E. coli, S. cerevisiae, H. salinarum, S. acidocaldarius, and H. sapiens), 3D gyration-tensor globular compactness gates (evaluate_globular_compactness), and Michaelis-Menten + Fluorapatite \(\text{Ca}_5(\text{PO}_4)_3\text{F}\) biomineralization simulators (simulate_defluorination_kinetics).

Conclusion

By merging Rust, PostgreSQL, and in-database graph/spatial/vector physics, we haven’t just built a database extension. We’ve built an autonomous, highly scalable operating system for synthetic biology and computational chemistry.

The days of moving biological and chemical data to the compute layer are over. With pg_bio, we are moving the compute directly to the data.

If you want to read about how we used this architecture to solve the 400-amino-acid limit on our Teflon-eating enzyme, check out Part 7 of the TeaFlon Series, or explore how we audited 4.5 microseconds of explicit-solvent MD trajectories in Auditing 500 ns Molecular Dynamics in SQL.


⚡ Powered by pg_bio on PostgreSQL 18 + Rust (pgrx): This discovery was executed natively inside PostgreSQL shared buffers using zero-copy Rust extensions (smith_waterman_score, 3D Kabsch SVD superposition, Z-Order B-Trees, and pgvector HNSW).

📚 Explore the Systems Architecture: PostgreSQL Query Planner & GiST R-Trees • Introducing pg_bio • Hybrid Operator <~> in Rust • The 27-Hour HNSW Index • More Bioinformatics Discoveries • Systems Research & CV

Jônatas Davi Paganini

Jônatas Davi Paganini

Jônatas Davi Paganini — Systems Researcher & Database Internals Engineer (20+ years experience). Creator of pg_bio (in-database structural biology & chemoinformatics engine for PostgreSQL in Rust) and spiral (geometry-aware multidimensional storage & Z-order indexing). Former Developer Advocate at Timescale.

1/1