Skip to main content

cached_duckdb

Fast in-memory DataFrame cache using DuckDB with SQL query interface.

Overview

cached_duckdb replaces pandas dict-based caching with DuckDB in-memory connections for:

  • Columnar storage - 20-30% less RAM than pandas
  • SQL queries - Single-pass filter+aggregate operations
  • Concurrency - Safe parallel reads during writes
  • Zero disk usage - Pure in-memory like pandas

Key Features

  • Generic database/table API - Works with any cache-based system
  • Two storage modes:
    • single_db: One connection per database (enables cross-table JOINs)
    • per_table_db: One connection per (database, table) pair (fully parallel writes)
  • Atomic swap - Readers see 100% old or 100% new data, never partial
  • TTL-based expiry - Background cleanup with lazy stale flagging
  • Scheduler-managed tables - Bypass TTL for scheduled updates
  • Thread-safe operations - Per-database or per-table locking

Installation

From PyPI (Recommended)

pip install cached-duckdb

Install Specific Version

pip install cached-duckdb==0.2.1

With Optional Protected Build Extras

pip install "cached-duckdb[all]"

From Local Source

pip install -r requirements.txt

Or install in development mode:

pip install -e .

Verify installed version:

import cached_duckdb
print(cached_duckdb.__version__)

Quick Start

Basic Usage

from cached_duckdb import DuckDbCacheManager
import pandas as pd

# Initialize cache (singleton)
cache = DuckDbCacheManager()

# Store DataFrame
df = pd.DataFrame({
    'date': ['2026-01-01', '2026-01-02'],
    'amount': [1000, 2000],
    'country': ['USA', 'UK']
})
cache.store(database="client_abc", table="sales_data", df=df)

# Query with SQL filtering
result = cache.query(
    database="client_abc",
    table="sales_data",
    sql_where="amount > 1000 AND country = 'USA'",
    columns=["date", "amount"]
)
print(result)

Advanced Queries

# Get all data
df = cache.query(database="app_x", table="dataset_1")

# Filter with WHERE
df = cache.query(
    database="app_x",
    table="dataset_1",
    sql_where="age > 25 AND country = 'USA'"
)

# Select specific columns
df = cache.query(
    database="app_x",
    table="dataset_1",
    columns=["name", "age", "salary"]
)

# Limit results
df = cache.query(
    database="app_x",
    table="dataset_1",
    sql_where="date >= '2026-01-01'",
    limit=100
)

Cross-Table JOINs (single_db mode)

# Execute raw SQL for complex queries
sql = """
    SELECT s.date, s.amount, o.customer_name
    FROM sales_data s
    JOIN orders o ON s.order_id = o.id
    WHERE s.amount > 1000
"""
result = cache.execute_sql(database="client_abc", sql=sql)

Check if Data Exists

if cache.exists(database="client_abc", table="sales_data"):
    # Data is ready and fresh
    df = cache.query(database="client_abc", table="sales_data")
else:
    # Data missing or stale - reload needed
    df = load_from_source()
    cache.store(database="client_abc", table="sales_data", df=df)

TTL and Scheduler-Managed Tables

# Store with custom TTL
cache.store(
    database="client_abc",
    table="sales_data",
    df=df,
    ttl_minutes=60  # Expires after 60 minutes
)

# Scheduler-managed table (no auto-expiry on reads)
cache.store(
    database="client_abc",
    table="sales_data",
    df=df,
    scheduler_managed=True  # Only scheduler updates it
)

Invalidate Cache

# Invalidate one table
cache.invalidate(database="client_abc", table="sales_data")

# Invalidate all tables for a database
cache.invalidate(database="client_abc")

Get Metadata

# Last updated timestamp
last_updated = cache.get_last_updated(database="client_abc", table="sales_data")
print(f"Last updated: {last_updated}")

# Table info
info = cache.get_table_info(database="client_abc", table="sales_data")
print(f"Rows: {info['row_count']}")
print(f"Columns: {info['columns']}")
print(f"Types: {info['column_types']}")

Documentation

Author

sreeyenan (sreeyenanek@gmail.com)

Version

Current version: 0.2.1

Configuration

Environment Variables

# Storage mode: single_db or per_table_db
CACHED_DUCKDB_DEFAULT_MODE=single_db

# Default TTL in minutes
CACHED_DUCKDB_DEFAULT_TTL_MINUTES=30

# Cleanup thread interval
CACHED_DUCKDB_CLEANUP_INTERVAL_MINUTES=5

# Lock timeout in seconds
CACHED_DUCKDB_LOCK_TIMEOUT_SECONDS=30

# Path to connector config file (optional)
CACHED_DUCKDB_CONFIG_FILE_PATH=/path/to/connector_config.json

# Logger name
CACHED_DUCKDB_LOG_NAME=cached_duckdb

Per-Database Configuration File

Create connector_config.json for per-database settings:

{
  "client_abc": {
    "duck_cache_mode": "per_table_db",
    "default_cache_ttl_minutes": 45,
    "sales_data": {
      "cache_ttl_minutes": 60,
      "scheduler_managed": false
    },
    "live_feed": {
      "cache_ttl_minutes": 0,
      "scheduler_managed": true
    }
  },
  "client_xyz": {
    "duck_cache_mode": "single_db"
  }
}

Priority order:

  1. Per-table config in JSON file (highest)
  2. Per-database config in JSON file
  3. Environment variables
  4. Hardcoded defaults (lowest)

Load Configuration

from cached_duckdb import DuckDbCacheConfig, DuckDbCacheManager

# From environment
config = DuckDbCacheConfig.from_env()
cache = DuckDbCacheManager(config)

# From dict
config = DuckDbCacheConfig.from_dict({
    "default_mode": "single_db",
    "default_cache_ttl_minutes": 30,
    "config_file_path": "/path/to/connector_config.json"
})
cache = DuckDbCacheManager(config)

Storage Modes

Mode A: single_db (Default)

  • One DuckDB connection per database
  • Multiple tables share the same connection
  • Enables cross-table SQL JOINs
  • Write contention: One lock per database

Use when: Database has few tables (< 20) or need cross-table queries

Mode B: per_table_db

  • One DuckDB connection per (database, table) pair
  • Each table is fully isolated
  • Zero write contention between tables
  • Fully parallel writes

Use when: Database has many tables (20+) or high write concurrency

Architecture

DuckDbCacheManager (singleton)
  ├── CacheStore        - Atomic writes, table management
  ├── CacheQuery        - SQL queries, metadata
  ├── TTLRegistry       - TTL tracking, cleanup thread
  └── CacheConfigResolver - Per-database config resolution

Thread Safety

  • store(): Write-locked per database or per table
  • query(): Lock-free parallel reads
  • invalidate(): Write-locked, waits for active readers
  • Background cleanup: Minimal locking, uses stale flags

Use Cases

  • Multi-tenant web APIs - Cache per tenant with database=tenant_id
  • Analytics dashboards - Fast in-memory OLAP queries
  • ETL pipelines - Store intermediate DataFrames
  • Session managers - Replace pandas dict caching
  • Microservices - Shared cache library across services

API Reference

DuckDbCacheManager

  • store(database, table, df, ttl_minutes=None, scheduler_managed=False) - Store DataFrame
  • query(database, table, sql_where=None, columns=None, limit=None) - Query with filtering
  • execute_sql(database, sql) - Execute raw SQL
  • exists(database, table) - Check if exists and fresh
  • invalidate(database, table=None) - Remove from cache
  • get_last_updated(database, table) - Get timestamp
  • get_table_info(database, table) - Get metadata
  • get_raw_connection(database, table=None) - Get DuckDB connection
  • shutdown() - Close all connections

Exceptions

  • DuckDbCacheError - Base exception
  • DuckDbCacheConfigError - Configuration error
  • DuckDbCacheLockError - Lock acquisition failed
  • DuckDbCacheNotFoundError - Table not found
  • DuckDbCacheStaleError - Data is stale

License

MIT License - see LICENSE file

Author

sreeyenan

Metadata

Release files for cached-duckdb 0.2.1

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

Source distribution (sdist)

Source distribution for cached-duckdb 0.2.1
File Size Uploaded
cached_duckdb-0.2.1.tar.gz 45.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cached-duckdb 0.2.1
File
cached_duckdb-0.2.1-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
cached_duckdb-0.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
cached_duckdb-0.2.1-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
cached_duckdb-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl CPython 3.11 CPython 3.11 macOS 10.9+ x86-64 Details

Total release size: 3.9 MB

Release files / cached_duckdb-0.2.1.tar.gz

Download URL cached_duckdb-0.2.1.tar.gz
Size 45.4 kB
Tags Source
SHA-256 checksum
How to use checksums
2881418e8a4d2db94e65ac010294f16125f1a4327d89a0bf7c2c5d7ff68a810e
BLAKE2b-256 checksum
How to use checksums
f7f31e4e623220fa190c315f9fb53b31e8ec8036802d22b9a5db9e0e1778b1f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 1, 2026.

Transparency log

Release files / cached_duckdb-0.2.1-cp311-cp311-win_amd64.whl

Download URL cached_duckdb-0.2.1-cp311-cp311-win_amd64.whl
Size 379.3 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
73fc3336e63fa51313a186801196eb0e26a877f933a23fb01931da2a69705f4d
BLAKE2b-256 checksum
How to use checksums
33b57878935a2d3f59988cf1d6475f062e700691658c10a6c10147add2fda489
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 1, 2026.

Transparency log

Release files / cached_duckdb-0.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl

Download URL cached_duckdb-0.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Size 2.6 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
87c288e860ce7885ffdd540cb679e3d1592e556b4918458d8f3f52dec62b64ef
BLAKE2b-256 checksum
How to use checksums
37f8159f3545de248aece390a29860150375784b455b2b33f2bbf011388b4085
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 1, 2026.

Transparency log

Release files / cached_duckdb-0.2.1-cp311-cp311-macosx_11_0_arm64.whl

Download URL cached_duckdb-0.2.1-cp311-cp311-macosx_11_0_arm64.whl
Size 417.9 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
61d08c51d8d23cb3ab3c54a5d91083971abb3e222e93936ee183ca565e29c036
BLAKE2b-256 checksum
How to use checksums
d0798c9bb2f535c4c0eb27b4b7c70d74536ba22bdc77e16249e8344843995661
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 1, 2026.

Transparency log

Release files / cached_duckdb-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl

Download URL cached_duckdb-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl
Size 428.2 kB
Tags CPython 3.11 macOS 10.9+ x86-64
SHA-256 checksum
How to use checksums
6ebb22c829b5c0199929c306974063e720a7bf0731bdae7e4606d2595f4d941b
BLAKE2b-256 checksum
How to use checksums
395c71539703418d11a28123989c7d702c361ea147823c91a9ac6125b9bc30f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

5 release files

0.2.0

6 release files

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