Kor Logo
Kor

Kor

A native, embedded key-value database — single-file, zero dependencies, blazing fast.

PyPI Python License Platform


Kor is a high-performance, embedded key-value database written in C++20 with a first-class Python SDK. Everything — metadata, records, write-ahead log — lives in a single .kr file. No sidecar files. No external dependencies. No server process. Just one file and sub-microsecond operations.

from kor import Database, db

# Create a database → get a secure HexToken
hex_token = Database("data", "users", 3)

# Connect and start working
client = db.connect("data", "users", hex_token)
client.set("user:1", ["Alice", 30, "Engineering"])
print(client.get("user:1"))  # ['Alice', 30, 'Engineering']
client.close()

Table of Contents


Why Kor?

Feature Kor Typical Embedded DBs
Storage Single .kr file Multiple files (WAL, meta, SSTs…)
Sidecar files Zero Often 3–10+
Authentication Built-in 128-bit HexToken None / bolted on
Atomic transactions ✅ Context manager Varies
Async support ✅ Native asyncio Rare
Multi-column values ✅ First-class Keys → single blob
Point-read speed 4.3 M ops/s ~161 K ops/s (RocksDB)
Deletion speed 10.7 M ops/s ~332 K ops/s (RocksDB)

Kor won 9 out of 9 benchmark tests against RocksDB at 10 million records. See Benchmarks.


Installation

pip install kor-db

Requires Python 3.10 – 3.14. Pre-built wheels available for Windows, Linux (manylinux 2.28), and macOS (10.15+) on x86-64.


Quick Start

from kor import Database, db

# 1. Initialize — creates "myapp/store.kr" and returns a hex token
hex_token = Database("myapp", "store", 3)   # 3 columns per key

# 2. Connect
client = db.connect("myapp", "store", hex_token)

# 3. Write records
client.set("user:1", ["Alice", 30, "Engineering"])
client.set("user:2", ["Bob", 25, "Design"])
client.set(key="user:3", c1="Charlie", c2=35, c3="Marketing")

# 4. Read records
print(client.get("user:1"))   # ['Alice', 30, 'Engineering']
print(client.get("unknown"))  # [None, None, None]  ← base null

# 5. Bulk operations (atomic)
client.set_many({
    "user:4": ["Diana", 28, "Sales"],
    "user:5": ["Eve", 32, "Security"],
})
results = client.get_many(["user:4", "user:5"])

# 6. Transactions
with client.transaction() as tx:
    tx.set("user:6", ["Frank", 40, "Legal"])
    tx.delete("user:5")
    # Commits on exit; rolls back on exception

# 7. Scan with pagination
page = client.scan(prefix="user:", limit=100)
for key, values in page["records"]:
    print(key, values)

# 8. Close — persists everything to the .kr file
client.close()

Core Concepts

The .kr Single-File Model

Kor stores everything in one file:

myapp/store.kr    ← Your entire database. One file. That's it.

No .wal, .meta, .info, .snap, .txn, or any other sidecar files. The .kr file contains the magic header, JSON metadata (hex token, column count, timestamps), and all records.

On open, data is loaded into RAM for sub-microsecond operations. On close, a consolidated snapshot is written atomically back to disk. Backup = copy one file. Migration = move one file.

HexToken Authentication

Every database is secured with a 128-bit cryptographic hex token:

hex_token = Database("data", "users", 3)
# Returns: '0x4f8a3c2e1b9d7e6f5a4b3c2d1e0f8a9b'
  • Generated once at creation, stored in the .kr metadata
  • Required for every connection — wrong token → AuthenticationError
  • Re-calling Database() on an existing file returns the stored token

Multi-Column Values

Each key maps to a fixed-width list defined at creation:

hex = Database("db", "employees", 3)  # 3 columns
client = db.connect("db", "employees", hex)

client.set("emp:1", ["Alice", 30, "Eng"])     # list format
client.set("emp:2", "Bob", 25, "Design")      # positional args
client.set(key="emp:3", c1="Charlie", c2=35, c3="Mkt")  # named columns

client.get("emp:1")  # ['Alice', 30, 'Eng']

Base Null Behavior

Missing keys return a null-filled list — not None, not an exception:

client.get("nonexistent")  # [None, None, None]

No Subscript Access

Subscript syntax is explicitly disabled with clear error messages:

client["key"]            # TypeError: 'Database' object is not subscriptable.
                         #   Use get() and set() methods instead.
client["key"] = value    # TypeError: 'Database' object does not support item assignment.
                         #   Use get() and set() methods instead.
del client["key"]        # TypeError: 'Database' object does not support item deletion.
                         #   Use get() and set() methods instead.

API Guide

Initialization & Connection

from kor import Database, db

# Initialize (creates .kr file, returns HexToken)
hex_token = Database("path", "name", number_of_values)

# Connect
client = db.connect("path", "name", hex_token)

Read & Write

# Set — three equivalent ways (raises DuplicateKeyError if key exists)
client.set("key", ["v1", "v2", "v3"])                    # list
client.set("key", "v1", "v2", "v3")                      # positional
client.set(key="key", c1="v1", c2="v2", c3="v3")         # named columns
# Explicitly replace an existing record:
client.set("key", ["v1", "v2", "v3"], overwrite=True)

# Get
client.get("key")                 # ['v1', 'v2', 'v3']
client.get("missing")            # [None, None, None]

# Delete & check
client.delete("key")
client.contains("key")           # False
client.count()                   # total records

Bulk Operations

# Raises DuplicateKeyError for any key that already exists
client.set_many({"k1": [1, 2, 3], "k2": [4, 5, 6]})
# To allow overwriting existing keys:
client.set_many({"k1": [1, 2, 3], "k2": [4, 5, 6]}, overwrite=True)
client.get_many(["k1", "k2"])             # [[1,2,3], [4,5,6]]
client.delete_many(["k1", "k2"])
client.contains_many(["k1", "k2"])        # [False, False]

Transactions

# Context manager — auto commit/rollback
with client.transaction() as tx:
    tx.set("k1", [1, 2, 3])
    tx.set(key="k2", c1=4, c2=5, c3=6)
    tx.delete("k3")

# Explicit control
tx = client.transaction()
tx.set("k1", [1, 2, 3])
tx.commit()   # or tx.rollback()

Scan & Pagination

cursor = None
while True:
    page = client.scan(prefix="user:", after=cursor, limit=100)
    for key, values in page["records"]:
        process(key, values)
    if not page["has_more"]:
        break
    cursor = page["next_cursor"]

Backup, Restore & Export

client.backup("backup/store.kr")
kor.restore("backup/store.kr", "data/store.kr", overwrite=True)
client.export_data("data.jsonl", format="jsonl")
client.import_data("data.jsonl", conflict="overwrite", atomic=True)

Async API

import kor

async with await kor.async_connect(path="data", name="store") as adb:
    await adb.set("user:1", ["Alice", 30, "Engineering"])
    print(await adb.get("user:1"))

    async with adb.transaction() as tx:
        await tx.set("user:2", ["Bob", 25, "Design"])

Other

client.storage_stats()                         # storage metrics
client.diagnostics()                           # runtime health
client.verify_integrity(level="structural")    # integrity check
db.connect("path", "name", hex, read_only=True)  # read-only mode

Benchmarks — Kor vs RocksDB

10 million records. Kor wins all 9 tests.

# Test Records Kor Ops/s RocksDB Ops/s Speedup
1 Sequential Bulk Ingestion 10,000,000 1,674,882 1,055,985 1.59×
2 Batched Bulk Ingestion (10K batches) 10,000,000 2,468,840 593,205 4.16×
3 Transactional Insertion 50,000 1,528,382 656,770 2.33×
4 Record Overwrites (Upserts) 100,000 2,131,397 785,840 2.71×
5 Point Queries (Reads) 50,000 4,329,044 161,103 26.87×
6 Single Unbatched Deletion 10,000 10,718,114 332,446 32.24×
7 Bulk Batched Deletion 200,000 25,413,223 3,698,812 6.87×
8 Transactional Deletion 50,000 10,530,507 1,286,890 8.18×
9 Prefix/Range Deletion 50,000 1,630,785 1,323,459 1.23×

Highlights: 26.87× faster reads · 32.24× faster deletes · 4.16× faster batch ingestion


Architecture

┌─────────────────────────┐
│   Python Application    │
└────────────┬────────────┘
             │
┌────────────▼────────────┐
│   kor (Python SDK)      │
│   Database · HexToken   │
│   Transactions · Async  │
└────────────┬────────────┘
             │
┌────────────▼────────────┐
│   _kor (pybind11)       │
│   C++20 ↔ Python bridge │
└────────────┬────────────┘
             │
┌────────────▼────────────┐
│   kor_engine (C++20)    │
│   Storage · WAL · Scan  │
│   Serialization         │
└────────────┬────────────┘
             │
┌────────────▼────────────┐
│   <name>.kr (ROM file)  │
│   Single-file database  │
└─────────────────────────┘

API Reference

Lifecycle

Method Returns Description
Database(path, name, num_values) HexToken Create/open database
db.connect(path, name, hex) Database Connect to database
client.close() — Persist & close

CRUD

Method Returns Description
set(key, value, *, overwrite=False) — Write columns (list / positional / named); raises DuplicateKeyError if key exists
get(key) list Read columns ([None,…] if missing)
delete(key) — Remove a key
contains(key) bool Key exists?
count() int Total records

Bulk (Atomic)

Method Returns Description
set_many(dict, *, overwrite=False) — Batch write; raises DuplicateKeyError for any existing key
get_many(list) list[list] Batch read (≤ 10,000 keys)
delete_many(list) — Batch delete
contains_many(list) list[bool] Batch existence check

Transactions

Method Returns Description
transaction() context manager Begin atomic transaction
tx.set(key, value) — Write in transaction
tx.delete(key) — Delete in transaction
tx.commit() — Commit explicitly
tx.rollback() — Roll back explicitly

Query & Maintenance

Method Returns Description
scan(prefix, after, limit) dict Paginated prefix scan
storage_stats() dict Storage metrics
diagnostics() dict Runtime health
verify_integrity(level) dict Check database integrity
backup(dest) dict Physical backup
export_data(dest) dict JSONL export
import_data(source) dict JSONL import

Exceptions

All importable from kor:

Exception When
AuthenticationError Hex token mismatch
DuplicateKeyError Key already exists and overwrite=False
InvalidConfigurationError Invalid config
PersistenceError Storage / I/O failure
RecoveryError WAL recovery failure
StorageClosedError Operation on closed database
ReadOnlyError Write on read-only connection
TransactionStateError Invalid transaction state
TransactionCommitError Commit failure
MemoryLimitExceededError Memory budget exceeded
InvalidKeyError Bad key format
InvalidValueError Bad value / column mismatch
SerializationError Serialization failure

Documentation

Document Description
Getting Started Installation, initialization, connection, first CRUD
API Reference Complete method reference with examples
Architecture & Internals .kr file format, ROM engine, storage model
Benchmarks Full 10M-record benchmark methodology and results

License

Copyright 2026 Pravanjan Roy (kingmon6996)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

<sub>Kor v0.1.0 · Built with C++20 + pybind11 · Made by Pravanjan Roy</sub>