Skip to main content

Kanta No-SQL database for async Python and frameworks such as FastAPI and Sanic

Project description

Kanta database

Kanta is a small embedded NoSQL store for async Python apps. It keeps live state in memory, writes transactional diffs to an append-only log, and supports versioned schema migrations.

Why Kanta

  • Fast synchronous reads and modifications on native Python objects
  • Durable writes with append-only file and periodic snapshots
  • Transaction semantics with rollback on failure
  • Explicit schema evolution via migrate_vN functions
  • Line-based JSON or binary MessagePack, or bring your own serializer
  • Even in JSON we can use non-string keys, bytes, datetimes, UUID and other types

This design is often preferable when you want low-latency local persistence without operating a separate database service. You get straightforward deployment, auditable history, and deterministic replay while keeping application state ergonomic to work with.

Queries and updates on native data are far faster than over an SQL server connection, and we can can provide fully synchronous operation. The limitation is that you can only use the same database within a single process at a time, but this is well suited for async programming.

Quick Start

import asyncio
import msgspec
from uuid import UUID, uuid7

from kanta import Kanta


class User(msgspec.Struct):
    name: str = ""
    email: str | None = None


class Data(msgspec.Struct):
    users: dict[UUID, User] = {}


async def main() -> None:
    async with Kanta("data.kantadb", Data()) as kanta:
        user_id = uuid7()
        with kanta.transaction(action="create_user") as data:
            data.users[user_id] = User(name="Alice")


asyncio.run(main())

Core Concepts

  1. Define your schema as a msgspec.Struct root object.
  2. Mutate data inside with kanta.transaction(...):.
  3. Let Kanta flush queued changes to disk in the background.
  4. Use snapshots and replay for fast startup and full history.

Bootstrap and Open Modes

Kanta supports open-time bootstrap callbacks for initializing a brand-new database before open() returns.

Register bootstrap handlers with a decorator:

kanta = Kanta("data.kantadb", Data())

@kanta.bootstrap(action="seed", user="system")
def seed_defaults(data) -> None:
    data.users["admin"] = User(name="Admin")

await kanta.open()

You can also use @kanta.bootstrap with no arguments and async handlers:

@kanta.bootstrap
async def bootstrap_async(data) -> None:
    data.counter = 1

When multiple bootstrap handlers are registered:

  • they run in registration order,
  • exactly one bootstrap change record is queued,
  • bootstrap metadata (action, user, mtime) is taken from the last registration.

If any bootstrap handler raises, Kanta closes and removes the database file, then re-raises the error.

open() also supports strict open mode:

await kanta.open(create=False)

With create=False, open fails if the database file does not exist or is empty.

Read-only mode opens an existing database without locking it or starting the background flush task. This is useful for readers that must not block the writer or modify the file:

await kanta.open(readonly=True)

In read-only mode, records are replayed and migrations are applied in memory, but transactions and explicit flushes are rejected and the file is never created if missing.

Fatal Error Handlers

Fatal background write errors can be observed with a decorator:

import os
import signal

@kanta.fatal_error
async def on_fatal(err):
    os.kill(os.getpid(), signal.SIGTERM)  # Die

Multiple fatal handlers are supported and run in registration order.

Migrations

Adding or removing a field and other such simple operations are automatic, but when the time comes to really change your data model, implement a migrate_v1 function that converts your old data to the new form. This works on plain built-in dict and other types, to avoid needing to preserve old versions of your structs.

Pass a module (or import path) containing migrate_vN functions:

kanta = Kanta("data.kantadb", Data(), migrations="myapp.migrations")
await kanta.open()

Kanta tracks migration version metadata automatically, and fast forwards your database to current version by running all the migrations needed while opening the database.

On-Disk Format

Kanta in JSON mode (default) stores newline-delimited records. Transaction history is viewable by any simple text editor, and rollbacks to prior state are done by simply removing final lines (one per transaction)

MsgPack mode uses binary records with length and checksum to avoid data corruption.

  • Change line: JSON object with metadata + diff
  • Snapshot line: SNAPSHOT { ... full state ... }

See docs/database.md for format details and invariants.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kanta-0.4.0.tar.gz (35.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kanta-0.4.0-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

File details

Details for the file kanta-0.4.0.tar.gz.

File metadata

  • Download URL: kanta-0.4.0.tar.gz
  • Upload date:
  • Size: 35.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kanta-0.4.0.tar.gz
Algorithm Hash digest
SHA256 57ae804f7b25db2803bff71e362beb2d307bda516e869f41adc8dee475e35ff1
MD5 a3db8d97e354714d01382eddad72ff46
BLAKE2b-256 b0119170e2402e6431d6d5cc2e1d403e092f109fca403491efb12ea8de68ce89

See more details on using hashes here.

File details

Details for the file kanta-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: kanta-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 32.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kanta-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fd1c872049a931b21faf23103c08d631145a3feca36e349f5b2647e904935539
MD5 85d3cccfc53e55361f42cd6a9b677bbf
BLAKE2b-256 57f7fe5d14193d8f71e8ce7c1deca86a51ef86cd3c5408695295ef875dc7a230

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page