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.

Periodic snapshot compaction keeps startup fast as a collection grows, by replaying a recent snapshot plus only the write-ahead log written since — not the full history of every write ever made.

Basic usage

Connect once, then read and write documents the way you'd expect from any document database.

index.js
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.

MethodArgumentsWhat 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).
Plus a handful of collection-level operations (call these on 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.

filters
{ total: { $gt: 100 } }

{ $and: [
  { stock: { $gte: 0 } },
  { stock: { $lte: 50 } },
] }

{ $or: [
  { status: "pending" },
  { status: "processing" },
] }

{ sku: { $regex: "^WH-" } }

{ discountCode: { $exists: true } }
updates
{ $set: { status: "shipped" } }

{ $unset: { discountCode: true } }

{ $inc: { stock: -1 } }
// negative values decrement

{ $push: { statusHistory: "shipped" } }
Supported operators: $eq $ne $gt $gte $lt $lte $in $nin $and $or $not $exists $regex

Example: 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.

orders.js
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 planTester: up to 3. Standard: up to 10. Business: up to 50. Each database can hold any number of collections.
Request body sizeEvery write request (insert, update, etc.) is capped at 5MB. Split very large imports into batches with insertMany instead of one oversized call.
Naming rulesDatabase and collection names must match ^[a-zA-Z0-9_-]{1,64}$ — letters, numbers, underscores, and hyphens, 1–64 characters.
Network accessA 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.

Ready to connect?

See plans & pricing