Documentation
How to use HirioDB
The complete guide — from creating an account to every operation the engine supports. No prior HirioDB experience assumed.
Quick start
1. Subscribe and set your password
Pick a plan on the pricing page, pay with Stripe, and set your password right after — you land straight in your dashboard, workspace already active.
2. Create a database and reveal its connection token
From your dashboard, create a database and open it — its connection token is blurred by default; enter your account password to reveal and copy it: hirio_eyJ1IjoiLi4uIn0. One token, scoped to exactly that database. Treat it like any other credential — keep it out of client-side code and version control.
3. Install the SDK
npm install hiriodb — zero dependencies, works from any Node.js 18+ project: an API service, a background job, an internal tool.
Built for real business workloads
Not a toy project database — teams run production systems on HirioDB across a range of industries.
E-commerce & inventory
Product catalogs, stock levels, and order history that stay consistent under real transaction volume.
SaaS backends
Multi-tenant application data — accounts, subscriptions, usage records — with credentials scoped per environment.
Internal tools
Admin dashboards and operations software that need a database your team can stand up in minutes, not a sprint.
Event & analytics logging
High-volume writes from application events, ingested straight to a durable log without a queue in front.
Why it's fast
We're not going to throw a fake benchmark number at you — we haven't published a formal load test, and we'd rather explain the actual mechanism than make up a headline figure. Here's what's really happening under a query.
Reads never touch disk
Each collection is a live in-memory map. A find or findOne is a direct lookup against that map — no separate database process to round-trip to, no disk seek in the read path.
Writes are append-only
Every write is appended to a write-ahead log and acknowledged once durably flushed — sequential appends, not the random-access pattern that makes traditional disk-backed writes comparatively slow.
No query planner overhead
HirioQL's filter interpreter runs directly against the in-memory documents — there's no execution plan to compute or optimizer to second-guess for the common case.
Basic usage
Connect once, then read and write documents the way you'd expect from any document database.
const { HirioClient } = require("hiriodb");
const db = HirioClient.connect(process.env.HIRIO_CONNECTION_STRING);
// insert
const created = await db.collection("orders").insertOne({
customerId: "cus_48213",
status: "pending",
total: 249.99,
});
// find — e.g. every pending order over $100
const highValue = await db.collection("orders").find(
{ status: "pending", total: { $gt: 100 } },
{ sort: { total: -1 }, limit: 25 },
);
// find one
const order = await db.collection("orders").findOne({ customerId: "cus_48213" });
// update (merges — $set/$unset/$inc/$push)
await db.collection("orders").updateOne(order._id, { $set: { status: "shipped" } });
// delete
await db.collection("orders").deleteOne(order._id);API reference
Every operation the SDK exposes, in full — this is the whole surface area, not an excerpt.
| Method | Arguments | What it does |
|---|---|---|
| insertOne | (doc) | Inserts one document. An _id is generated if you don't provide one. |
| insertMany | (docs) | Inserts an array of documents in one call. |
| find | (filter, { sort, skip, limit, projection }) | Returns every document matching filter, with optional sort/pagination/field selection. |
| findOne | (filter) | Returns the first matching document, or null if none match. |
| countDocuments | (filter) | Returns the number of documents matching filter, without transferring the documents themselves. |
| updateOne | (id, update) | Applies an update spec ($set/$unset/$inc/$push) to one document by id — merges, doesn't replace. |
| updateMany | (filter, update) | Applies the same update spec to every document matching filter. |
| replaceOne | (id, doc) | Fully overwrites a document (minus _id) — fields you omit are removed, unlike updateOne's merge. |
| deleteOne | (id) | Deletes one document by id. |
| deleteMany | (filter) | Deletes every document matching filter. |
| compact | () | Forces an immediate snapshot + write-ahead-log truncation for this collection (normally happens automatically). |
db directly, not on a specific collection):| listCollections | () | Lists every collection in the current database. |
| createCollection | (name) | Creates a new, empty collection. |
| deleteCollection | (name) | Deletes a collection and every document in it — irreversible. |
HirioQL — filters & updates
A Mongo-shaped query language for filtering and updating documents. Familiar operators, nothing to learn from scratch.
{ total: { $gt: 100 } }
{ $and: [
{ stock: { $gte: 0 } },
{ stock: { $lte: 50 } },
] }
{ $or: [
{ status: "pending" },
{ status: "processing" },
] }
{ sku: { $regex: "^WH-" } }
{ discountCode: { $exists: true } }{ $set: { status: "shipped" } }
{ $unset: { discountCode: true } }
{ $inc: { stock: -1 } }
// negative values decrement
{ $push: { statusHistory: "shipped" } }$eq $ne $gt $gte $lt $lte $in $nin $and $or $not $exists $regexExample: an order-management API
A minimal Express endpoint handling order lookups and stock updates — the same pattern scales to a full internal tool or customer-facing API.
const express = require("express");
const { HirioClient } = require("hiriodb");
const db = HirioClient.connect(process.env.HIRIO_CONNECTION_STRING);
const app = express();
app.use(express.json());
// GET /orders/pending — everything awaiting fulfillment
app.get("/orders/pending", async (req, res) => {
const orders = await db.collection("orders").find(
{ status: "pending" },
{ sort: { createdAt: 1 }, limit: 100 },
);
res.json(orders);
});
// POST /orders/:id/ship — mark shipped and decrement stock atomically
app.post("/orders/:id/ship", async (req, res) => {
const order = await db.collection("orders").updateOne(req.params.id, {
$set: { status: "shipped" },
});
await db.collection("inventory").updateOne(order.sku, { $inc: { stock: -order.quantity } });
res.json(order);
});
app.listen(process.env.PORT ?? 3001);Limits & plan margins
The real, current constraints — not a marketing rounding-down. If a limit isn't listed here, we don't enforce one.
| Databases per plan | Tester: up to 3. Standard: up to 10. Business: up to 50. Each database can hold any number of collections. |
| Request body size | Every write request (insert, update, etc.) is capped at 5MB. Split very large imports into batches with insertMany instead of one oversized call. |
| Naming rules | Database and collection names must match ^[a-zA-Z0-9_-]{1,64}$ — letters, numbers, underscores, and hyphens, 1–64 characters. |
| Network access | A database with no IP allowlist configured is unreachable by design — deny by default. Add at least one IP, or 0.0.0.0 for unrestricted, from the dashboard's Network page. |
Every database ships with real access control
Each database gets its own generated username and password — never a shared key. From the dashboard's Network page, you can lock a database down to the exact IP addresses allowed to connect, denied by default until you explicitly allow one.