User Guide
Everything you need to install, configure, and build with Montycat — from getting started to governance, advanced operations, and security.
Store / Keyspace
Create store
A store is a logical container for one or more keyspaces (both persistent and not persistent).
Conceptually, a store can be compared to a branch of a company, where each keyspace functions as a department within that branch.
Stores are created automatically when a keyspace is initialized, so manual creation is not required in most cases.
If necessary, a store can also be created manually using the CLI.
During this process, you will be prompted for authentication credentials.
Note: Creating a store typically requires superowner privileges.
montycat console
> create-store store <store name>
exitRemove store
Warning: if you remove a store all the keyspaces it contains and their indexes will be removed.
Note: Removing a store typically requires superowner privileges.
montycat console
> remove-store store <store name>
exitUse clients API to create / remove stores
Examples for clients:
from montycat import Engine, Keyspace
connection = Engine(
host="<host>",
port=<port>,
username="<username>",
password="<password>",
store="<store name>"
)
# call in async runtime
res1 = await connection.create_store()
res2 = await connection.remove_store()
# {"status": True, "payload": None, "error": None}Keyspaces
Keyspaces are structures within each store.
A keyspace in Montycat is the top-level namespace for data storage.
Think of it as:
- A database in traditional SQL systems;
- A bucket in object storage systems like S3;
- A logical boundary that separates and organizes data under a single store.
Volumes inside Keyspaces
Within every keyspace, Montycat automatically manages volumes.
Volumes are elementary data containers handling the actual physical storage of records.
They are self-managing: Montycat creates, grows, and retires volumes transparently without requiring user intervention.
This makes keyspaces highly scalable and efficient, since the system can split and balance data across multiple volumes as needed.
Why Keyspaces Matter
- Isolation: Each keyspace provides isolation, so different applications, services, or datasets can coexist within the same store without conflict.
- Organization: Keyspaces let you group related data in a clean and structured way.
- Flexibility: You can define one or many keyspaces depending on your workload - from simple single-namespace storage to multi-tenant systems.
- Scalability: With volumes managed internally, keyspaces can hold extremely large datasets without requiring the user to think about partitioning.
Example Use-Cases
- Multi-Tenant SaaS: Each tenant gets its own keyspace. The keyspace is the namespace boundary, and credentials are scoped to it, so one tenant’s data is not reachable through another tenant’s credentials.
- Data Domains: Analytics workloads can use different keyspaces for finance, operations, and user behavior.
- Hybrid Models: One keyspace for fast in-memory data, another for persistent storage and so on.
Keyspaces and the Data Mesh Philosophy
Montycat is designed to fit naturally into data mesh architecture.
A data mesh promotes domain-oriented decentralized data ownership and treats data as a product.
Each keyspace can represent a domain in the organization (e.g., finance, sales, sensors, users), or a tenant in a multi-tenant deployment.
Keyspaces act as bounded contexts: a keyspace is its own namespace, and the data inside it is reached only through credentials scoped to it.
Because Montycat supports schema-flexible storage, teams can evolve their domain’s data model at their own pace, without disrupting other domains.
Domains interoperate through explicit, modelled references rather than an implicit federation layer: pointers declared in a schema resolve records across keyspaces on request, so data stays physically separated but can be read as one hydrated object.
Autonomy is delegated, not assumed. Two separate mechanisms decide what a team can do:
- Data access — the
read,write, and store-wideallpermissions described under Credentials decide who can read and write records in a keyspace. - Administrative authority — governance policies decide who may provision, remove, snapshot, or reconfigure a keyspace. A superowner delegates these capabilities per store and per keyspace; they never imply data access.
In short: keyspaces give teams a bounded context of their own, while credentials and governance define exactly how much autonomy each team has inside it. See Data-mesh governance for the policy model and Data Mesh for the architectural overview.
Create a keyspace for in-memory data
To create a keyspace use:
montycat console
> create-keyspace store <store name> keyspace <keyspace name>
exitCreate persistent keyspace
If you put persistent in the end keyspace you are going to create will be persistent.
The cache is an optional argument, it has to be more than 10 MB, if set to a value less than 10 MB - it will fall back to 10 MB.
The last argument also is optional. It represents compression and if present will set compression of data to true.
montycat console
> create-keyspace store <store name> keyspace <keyspace name> persistent cache 100 compression
exitClients API
Examples for clients:
from montycat import Engine, Keyspace
connection = Engine.from_uri(
"montycat://<username>:<password>@<host>:<port>/<store name>"
)
class Employees(Keyspace.Persistent):
keyspace = "Employees"
cache = 100 #optional
compression = True # optional
class EmployeesInMem(Keyspace.InMemory):
keyspace = "EmployeesInMem"
Employees.connect_engine(connection)
EmployeesInMem.connect_engine(connection)
res1 = await Employees.create_keyspace()
res2 = await EmployeesInMem.create_keyspace()
# {"status": True, "payload": None, 'error': None}Cache and compression updating
You can update cache size and optionally enable or disable compression for an existing persistent keyspace.
- cache - defines the cache capacity (in MB).
This value controls how much memory Montycat allocates for hot data to improve query performance. - compression - if flag set, compression will be enabled for the keyspace.
Important: cache size and compression flag changes require restart.
montycat console
> update-cache-compression store <store name> keyspace <keyspace name> cache 500 compression
exitClients API
Use clients to update cache and compression:
from montycat import Engine, Keyspace
connection = Engine.from_uri("montycat://<username>:<password>@<host>:<port>/<store name>")
class Employees(Keyspace.Persistent):
keyspace = "Employees"
cache = 500 # was 100
compression = False # was true
Employees.connect_engine(connection)
res1 = await Employees.update_cache_and_compression()
# {"status": True, "payload": None, "error": None}Get Available Structure
Method is useful to preview all the existing stores and keyspaces.
Returns a JSON object with current structure.
from montycat import Engine, Keyspace
connection = Engine.from_uri("montycat://<username>:<password>@<host>:<port>")
res1 = await connection.get_structure_available()
# {"status": True, "payload": <JSON tree of all available structures>, "error": None}Keyspace Length
Get number of records within a particular keyspace.
Typically returns a JSON object with number of records and volumes.
from keyspaces import Employees, EmployeesInMem #keyspaces.py
res1 = await Employees.get_len()
res2 = await EmployeesInMem.get_len()
# {"status": True, "payload": <JSON object with length and other metadata>, "error": None}Remove a Keyspace
Remove keyspaces.
Make sure you put persistent if your target for removal was a persistent keyspace.
Warning: removing a keyspace will delete all the data and indexes associated with it. Operation cannot be reverted.
CLI command will require superowner privileges.
montycat console
> remove-keyspace store <store name> keyspace <keyspace name> persistent
exitRemove a Keyspace With Clients API
Use clients to remove a keyspace:
from keyspaces import Employees, EmployeesInMem #keyspaces.py
res1 = await Employees.remove_keyspace()
res2 = await EmployeesInMem.remove_keyspace()
# {"status": True, "payload": None, "error": None}