Getting Started

Quick Start

Get Zerobase running in under a minute. No server, no config, no database engine — just SQL over plain JSON files.

Requires Node.js 14+. Zero native dependencies — installs in seconds.

Installation

BASH
$ npm install zerobase-cli

# or globally
$ npm install -g zerobase-cli

Initialize

Run inside your project directory. Creates ./storage/ with an empty schema.json. Safe to run multiple times.

BASH
$ zerobase init
  Zerobase initialized → ./storage/
  › Open the SQL shell:  zerobase query
  › Or use in Node.js:   const db = require('zerobase-cli')

Your first query

SQL SHELL
$ zerobase query

zerobase› CREATE TABLE users (id INT PRIMARY KEY, name TEXT, age INT);
  Table users created  (3 columns, 2ms)

zerobase› INSERT INTO users (name, age) VALUES ('Kunal', 20);
  1 row inserted into users  · id: 1  (1ms)

zerobase› SELECT * FROM users;
  ┌────┬───────┬─────┐
  │ id │ name  │ age │
  ├────┼───────┼─────┤
  │  1 │ Kunal │  20 │
  └────┴───────┴─────┘
  1 row(s) returned · 1ms

CLI Reference

CLI Commands

The Zerobase CLI gives you a full set of commands for managing storage and running SQL from any terminal.

zerobase initSETUP

Initialize storage in the current directory. Creates ./storage/ and schema.json.

$ zerobase init
zerobase querySHELL

Open the interactive SQL shell with ↑↓ history, multi-line buffering, and dot-commands.

$ zerobase query
zerobase tablesINFO

List all tables with column count and primary key info.

$ zerobase tables
zerobase describe <table>INFO

Show column names, types, constraints, and the current row count for a table.

$ zerobase describe users
zerobase drop <table>DESTRUCTIVE

Drop a table and permanently delete its JSON file. Equivalent to DROP TABLE in SQL.

$ zerobase drop users

Shell meta-commands

Inside the zerobase query shell, these commands work without SQL syntax:

Command Description
.tables List all tables
.describe <table> Show schema and row count
.drop <table> Drop a table
.history Show last 20 queries from history file
.help Show all available commands
.exit Exit the shell (also: exit, quit)

Query History

The shell persists your query history to ~/.zerobase_history (up to 100 entries). Use and arrow keys to navigate. Run .history to see recent entries inline.


SQL Reference

SQL Reference

A precise, complete subset of SQL. Every statement is parsed by a regex-based engine — lightweight, fast, and fully auditable.

CREATE TABLE

Define a new table with typed columns. Declare one column as PRIMARY KEY and Zerobase will auto-increment it on every insert.

SQL
CREATE TABLE tableName (
  colName  TYPE [PRIMARY KEY],
  colName  TYPE
);

-- Concrete example
CREATE TABLE products (
  id     INT PRIMARY KEY,
  name   TEXT,
  price  FLOAT,
  active BOOL
);
Creates ./storage/products.json (empty array) and registers the schema in schema.json.

DROP TABLE

Permanently removes the table's schema entry and deletes its JSON data file.

SQL
DROP TABLE products;
Irreversible. The JSON file is deleted from disk immediately.

INSERT INTO

Insert a row. Values are matched positionally to columns. String values must be single-quoted. Omit the primary key column — Zerobase assigns the next integer automatically.

SQL
INSERT INTO tableName (col1, col2) VALUES (val1, val2);

-- Strings must be single-quoted
INSERT INTO users (name, age) VALUES ('Kunal', 20);
-- id auto-assigned → 1

-- Multiple types
INSERT INTO products (name, price, active) VALUES ('Widget', 9.99, 1);

SELECT

Query rows from a table. Supports column projection, WHERE conditions, ORDER BY, LIMIT, and aggregate functions.

SQL
-- All columns
SELECT * FROM users;

-- Specific columns
SELECT name, age FROM users;

-- Column alias
SELECT name AS full_name FROM users;

WHERE & Logic

Filter rows with one or more conditions. Chain with AND or OR.

SQL
-- Single condition
SELECT * FROM users WHERE age > 18;

-- AND
SELECT * FROM users WHERE age > 18 AND name = 'Kunal';

-- OR
SELECT * FROM users WHERE age < 18 OR age > 65;

-- Supported operators: =  !=  >  <  >=  <=

ORDER BY & LIMIT

SQL
SELECT * FROM products ORDER BY price DESC;
SELECT * FROM users ORDER BY name ASC LIMIT 10;

-- Combined with WHERE
SELECT * FROM products
  WHERE active = 1
  ORDER BY price DESC
  LIMIT 5;

Aggregates

Compute statistics across filtered rows. Combine multiple aggregates in one SELECT. Use AS for readable column names in results.

SQL
SELECT COUNT(*) FROM users;
SELECT SUM(price) FROM products;
SELECT MIN(age), MAX(age), AVG(age) FROM users;

-- Aliases + WHERE
SELECT
  COUNT(*)   AS total,
  AVG(price) AS avg_price,
  MAX(price) AS highest
FROM products
WHERE active = 1;

UPDATE

Update columns on matching rows. WHERE is required — Zerobase rejects UPDATE without a condition to prevent accidental full-table overwrites.

SQL
UPDATE users SET age = 25 WHERE id = 1;

-- Multiple columns
UPDATE users SET age = 25, name = 'Kunal V' WHERE id = 1;

DELETE

Remove matching rows. Without WHERE, all rows are deleted (the table and its schema remain).

SQL
DELETE FROM users WHERE id = 3;
-- Clear all rows (table stays)
DELETE FROM users;

Runtime SDK

Node.js SDK

Use Zerobase directly in your app with require('zerobase-cli'). The SDK runs the same SQL engine as the CLI — same storage, same results.

Make sure zerobase init has been run in your project root before using the SDK. The SDK reads from ./storage/ relative to wherever Node.js is invoked.

db.query(sql)

Runs any SQL statement and returns a Promise resolving to a result object. The shape of the result depends on the query type.

JSapp.js
const db = require('zerobase-cli');

// INSERT → { message, inserted, primaryKey }
const r1 = await db.query("INSERT INTO users (name, age) VALUES ('Priya', 22)");
console.log(r1.inserted);     // { id: 2, name: 'Priya', age: 22 }

// SELECT → { rows: Array, count: number }
const r2 = await db.query("SELECT * FROM users WHERE age > 18");
console.log(r2.rows);         // [{ id:1, name:'Kunal', age:20 }, ...]
console.log(r2.count);        // 2

// UPDATE → { message, updatedCount }
const r3 = await db.query("UPDATE users SET age = 23 WHERE id = 1");
console.log(r3.updatedCount); // 1

// DELETE → { message, deletedCount }
const r4 = await db.query("DELETE FROM users WHERE id = 3");
console.log(r4.deletedCount); // 1

db.select(sql)

Shorthand for SELECT queries — returns the rows array directly instead of a result wrapper object.

JS
// Returns Array directly (not { rows, count })
const rows = await db.select("SELECT * FROM users ORDER BY age DESC LIMIT 5");
console.log(rows[0].name); // 'Priya'

Reference

Reference

Data Types

SQL Type JS Type Notes
INT number Integers. Good for IDs, ages, counts.
FLOAT number Decimal values. Good for prices, ratios.
TEXT string Any string. Must be single-quoted in SQL.
BOOL boolean Use 1 / 0 in SQL. Stored as true/false in JSON.

WHERE Operators

Op Meaning Works with
= Equal to INT, FLOAT, TEXT, BOOL
!= Not equal to INT, FLOAT, TEXT, BOOL
> Greater than INT, FLOAT
< Less than INT, FLOAT
>= Greater than or equal INT, FLOAT
<= Less than or equal INT, FLOAT

Storage Format

All data lives in ./storage/ relative to your project root. Zerobase finds this folder by walking up from the current directory — so zerobase query works from any subdirectory, like src/routes/ or tests/.

STRUCTURE
./storage/
  schema.json      ← table definitions + column types
  users.json       ← row data for "users"
  products.json    ← row data for "products"
JSONschema.json
{
  "users": {
    "columns": {
      "id":   "number",
      "name": "string",
      "age":  "number"
    },
    "primaryKey": "id"
  }
}

Error Reference

Every error includes the problem, expected format, and a working example.

Unknown command: "DROP".
Hint: Did you mean: DROP TABLE tableName;
Column "email" does not exist in table "users".
Available columns: id, name, age
Type mismatch on "age": expected number, got string.
Hint: Numbers should not be quoted — use 20, not '20'.
UPDATE requires a WHERE clause.
Example: UPDATE users SET age = 25 WHERE id = 1;
Column/value count mismatch: 3 column(s) but 2 value(s).

Limitations

Zerobase is designed for local development, prototyping, and offline tools — not production workloads with concurrent writes.
  • No JOIN — queries are single-table only
  • No concurrent write safety — one process at a time
  • No transactions or rollbacks
  • No nested WHERE groups — AND/OR chains only
  • No subqueries or nested SELECT
  • No GROUP BY — use WHERE to pre-filter then aggregate
  • No indexes — queries scan the full JSON array linearly
  • Practical limit ~10,000 rows per table before performance degrades