Skip to Content
SQL ReferenceStorage ID Usage

Storage ID Usage

Use this guide when you want to control where table data is stored, pick storage per table, and understand user-table routing behavior.

For MinIO-specific S3-compatible setup, see MinIO (S3-Compatible).

Create storage backends first

Before using STORAGE_ID in CREATE TABLE, the storage must exist in system.storages.

Filesystem storage

sql snippetSQL
CREATE STORAGE local_archive    TYPE filesystem    NAME 'Local Archive'    DESCRIPTION 'Filesystem storage for archived tables'    PATH './data/storage/local-archive'    SHARED_TABLES_TEMPLATE 'shared/{namespace}/{tableName}'    USER_TABLES_TEMPLATE 'users/{namespace}/{tableName}/{userId}';

PATH is supported for filesystem storage. BASE_DIRECTORY is also accepted.

S3 storage

sql snippetSQL
CREATE STORAGE s3_prod    TYPE s3    NAME 'Production S3'    DESCRIPTION 'S3 bucket for production data'    BUCKET 'my-kalamdb-prod-bucket'    REGION 'us-east-1'    SHARED_TABLES_TEMPLATE 'shared/{namespace}/{tableName}'    USER_TABLES_TEMPLATE 'users/{namespace}/{tableName}/{userId}';

For S3, you can use either:

  • BUCKET 'bucket-name' (optionally with REGION)
  • BASE_DIRECTORY 's3://bucket/prefix'

Useful checks:

sql snippetSQL
SHOW STORAGES;SELECT storage_id, storage_type, storage_name FROM system.storages;

Use STORAGE_ID in CREATE TABLE

KalamDB accepts STORAGE_ID in WITH (...) table options.

Shared table with explicit storage

sql snippetSQL
CREATE TABLE app.config (    key TEXT PRIMARY KEY,    value TEXT) WITH (    TYPE = 'SHARED',    STORAGE_ID = 's3_prod');

User table with explicit storage and flush policy

sql snippetSQL
CREATE TABLE app.messages (    id BIGINT PRIMARY KEY DEFAULT SNOWFLAKE_ID(),    content TEXT,    created_at TIMESTAMP DEFAULT NOW()) WITH (    TYPE = 'USER',    STORAGE_ID = 'local_archive',    FLUSH_POLICY = 'rows:5000');

If STORAGE_ID is omitted

If omitted, KalamDB resolves storage to local by default.

sql snippetSQL
CREATE TABLE app.metrics (    id BIGINT PRIMARY KEY,    value DOUBLE) WITH (TYPE = 'SHARED');

Verify table storage metadata

Inspect table metadata in system.schemas:

sql snippetSQL
SELECT namespace_id, table_name, table_type, storage_id, use_user_storageFROM system.schemasWHERE namespace_id = 'app' AND is_latest = trueORDER BY table_name;

Per-user storage routing (USE_USER_STORAGE)

For USER tables, you can enable per-user storage routing metadata:

sql snippetSQL
CREATE TABLE app.geo_events (    event_id BIGINT PRIMARY KEY DEFAULT SNOWFLAKE_ID(),    payload JSON,    created_at TIMESTAMP DEFAULT NOW()) WITH (    TYPE = 'USER',    STORAGE_ID = 's3_prod',    USE_USER_STORAGE = true);

Rules:

  • USE_USER_STORAGE is valid only for TYPE = 'USER'
  • STORAGE_ID remains fallback storage for the table
  • User preference fields exist in system.users (storage_mode, storage_id)

Changing storage per user (current status)

Current SQL behavior:

  • DML against system.* tables is blocked
  • ALTER USER currently supports only SET PASSWORD, SET ROLE, and SET EMAIL

So there is no public SQL command yet to directly update a user’s storage_mode or storage_id.

Current developer workflow:

  • Set table-level routing with STORAGE_ID (optionally USE_USER_STORAGE)
  • For user-level overrides, use internal/admin backend flows

Common failures

Unknown storage ID

sql snippetSQL
CREATE TABLE app.bad_example (    id INT PRIMARY KEY) WITH (TYPE = 'SHARED', STORAGE_ID = 'does_not_exist');

Expected error pattern:

text snippetTEXT
Storage 'does_not_exist' does not exist

Invalid USE_USER_STORAGE on non-user table

sql snippetSQL
CREATE TABLE app.bad_shared (    id INT PRIMARY KEY) WITH (TYPE = 'SHARED', USE_USER_STORAGE = true);

Expected error pattern:

text snippetTEXT
USE_USER_STORAGE is only supported for USER tables
Last updated on