In development· Milestone M1 in progress
Your data, in the shape it already has.
Self-hosted and open source, for dashboards and analysis. Tables stay tables, documents stay documents, graphs stay graphs.
- Start
- Dashboards
- Explore
- Data sources
- Administration
Dashboards /
Orders of customer C-1042
Sample dataOrder value over timeframe
Customers linked by a productgraph
Order documentdocuments
- _idObjectId
- customerId"C-1042"
- itemsArray(2)
- sku"P-20"
- priceDecimal128
- shipping{ 1 }
Field coveragedocuments
- _id
- customerId
- createdAt
- items
- items[].sku
- items[].price
Works with
- PostgreSQL
- MySQL
- MariaDB
- SQL Server
- SQLite
- MongoDB
- Neo4j
- Memgraph
- Prometheus
- Elasticsearch
One question, three answers
What did customer C-1042 order?
SELECT id, created_at, items, total
FROM orders
WHERE customer_id = 'C-1042'
ORDER BY created_at;| idtext | created_attimestamptz | itemsint4 | totalnumeric |
|---|---|---|---|
| O-77 | 2026-09-02 10:14 | 3 | 129.90 |
| O-84 | 2026-09-15 18:02 | 1 | 24.00 |
| O-90 | 2026-10-03 08:47 | 2 | 89.50 |
Rows and typed columns
- Columns keep their database types.
- Time series and metrics are frames too, with a time field.
- The first frame sources arrive in M1.
db.orders.find({ customerId: "C-1042" })Document · documents
- _id66f5a1c2e4b0…ObjectId
- customerId"C-1042"string
- createdAt2026-09-02T10:14:00ZDate
- itemsArray(2)
- 0{ 3 }
- sku"P-20"string
- qty1int32
- price49.90Decimal128
- 1{ 3 }
- sku"P-31"string
- qty2int32
- price40.00Decimal128
- 0{ 3 }
- shipping{ 1 }
- address{ 1 }
- city"Leipzig"string
- address{ 1 }
| Path | Types | In documents |
|---|---|---|
| _id | ObjectId | 100% |
| customerId | string | 100% |
| createdAt | Date | 100% |
| items | array 1–4 | 100% |
| items[].sku | string | 100% |
| items[].price | Decimal128 92%double 8% | 100% |
| shipping.address.city | string | 97% |
| giftNote | string | 3% |
The document tree and its schema
- Nested arrays stay arrays you can drill into.
ObjectId,DateandDecimal128keep their types instead of turning into strings.- The schema view lists every field path with its types and how many documents have it.
- MongoDB arrives in M2.
MATCH p = (:Customer {id: "C-1042"})-[:ORDERED]->(:Order)
-[:CONTAINS]->(:Product)<-[:CONTAINS]-(:Order)
<-[:ORDERED]-(:Customer)
RETURN p LIMIT 25Path · graph
- CustomerC-1042
- ORDERED
- OrderO-77
- CONTAINS
- ProductP-20
- CONTAINS
- OrderO-63
- ORDERED
- CustomerC-2210
Nodes, edges and the path between them
- Paths come back as paths, readable node by node.
- The rest of the graph dims; the path keeps its labels.
- Explore by expanding neighbours, one undoable step at a time.
- Neo4j and Memgraph arrive in M3.
Illustration with sample data, not a screenshot.
01The idea
Nothing gets flattened behind your back.
Many tools turn every result into a table. Nested documents become columns, graphs become a list of nodes and a list of edges, and the structure you came for is gone. In Kalzit every query result keeps exactly one native shape: frame, documents or graph. Panels declare which shapes they understand.
02Projections
Conversions are steps you can see.
Sometimes you do want a time series from documents. Then you add a projection step to the query, for example $.metrics.cpu over $.ts. The step stays in the query, you can undo it, and the original documents remain available. The backend never converts on its own.
- documentsorders
- Projection
$.metrics.cpuover$.ts - frametime series
- Visible in the query
- Undoable
- Original stays available
Transformations follow the shape as well: pick a field, unwind an array or group by a field path for documents; expand a neighbourhood, filter a subgraph or merge nodes for graphs.
03Data sources
Common sources, each in its own shape.
Relational and time-series sources answer in frames, MongoDB in documents, Neo4j and Memgraph in graphs. Every source is read-only by default: the server rejects write queries, and queries always run on the server, never from the browser to the database.
No data source is available yet. The first ones arrive with M1.
| Milestone | Source | Shape |
|---|---|---|
| M1 | PostgreSQL, TimescaleDB | frame |
| MySQL, MariaDB | frame | |
| Microsoft SQL Server | frame | |
| SQLite | frame | |
| Prometheus, Mimir, Thanos, VictoriaMetrics | frame | |
| M2 | MongoDB | documents |
| Elasticsearch, OpenSearch | documentsframe | |
| CSV, JSON, HTTP JSON | framedocuments | |
| M3 | Neo4j, Memgraph | graph |
| M5 | InfluxDB | frame |
| Loki | frame | |
| ClickHouse | frame | |
| M6 | Graphite | frame |
| Redis | framedocuments | |
| Oracle | frame | |
| Tempo, Jaeger | graph |
04Organizations, teams, roles
Access is decided on the server, every time.
One installation hosts several organizations. Each has its own teams, folders, dashboards and data sources.
- Two levels of roles
- Server admins run the installation. Inside an organization, owner, admin, editor and viewer are fixed roles, and you can build your own roles from fine-grained permissions.
- No permission without a reason
- Effective permissions are the union of role, team roles and direct shares. A “Why can I do this?” dialog shows where each one comes from. The default is no access, and the last owner and the last server admin cannot be removed.
- Checked on every request
- Authorization runs on the server for every request and every resource, never only in the UI.
- Server settings in layers
- Environment variables win over the configuration file, which wins over settings changed in the UI. Network and TLS settings live only in the file or the environment, so a typo in the UI cannot lock you out.
- Sign-in
- Local accounts with Argon2id are part of M0. OIDC, LDAP and Active Directory, two-factor sign-in with TOTP and passkeys follow in M5.
05Windows and Linux
One binary, two first-class platforms.
Kalzit is a single Rust binary with the web UI embedded. Windows and Linux are equal: CI runs every build and every test on both. Planned release targets are Windows x64, Linux x64 and Linux arm64.
Windows
- Configuration in
%ProgramData%\Kalzit\kalzit.toml - Windows service and MSI installer in M5
- SQL Server in M1, Active Directory sign-in in M5
Linux
- Configuration in
/etc/kalzit/kalzit.toml - deb and rpm packages with a systemd unit in M5
- Docker image in M5
HTTPS built in
TLS through rustls: the same code on both systems and no OpenSSL to install. Renewed certificate files are picked up without a restart. ACME with Let’s Encrypt follows in M5.
No database server to start
Kalzit keeps its own data in SQLite by default. Larger installations use PostgreSQL.
06Open source
AGPL-3.0, self-hosted, no telemetry.
The complete source is public under the GNU Affero General Public License 3.0. Kalzit runs only on your own servers; there is no cloud offering. Checking for updates is off until you turn it on, and there is no telemetry.
- Written from scratch as a clean-room implementation.
- Built-in data sources use the same plugin interface as external plugins (M4).
- Plugins are signed with Ed25519; unsigned plugins need an admin’s approval.
- Plugin SDK in Rust first, then TypeScript and Go.
07Status
Early, and honest about it.
Kalzit is being built in public, milestone by milestone. Every milestone ends with green CI on Windows and Linux and documentation for each new feature.
08The name
Why Kalzit
Kalzit is German for calcite. Its clearest form, Iceland spar, splits every ray of light in two, so whatever lies behind it shows up twice. Vikings may have used it as a sunstone to find the sun under a cloudy sky. That is the job we want Kalzit to do for data: make hidden structure visible.
Follow the work from the start.
Watch the repository for releases, read the plan, or open an issue about the data you want to explore.
