HeliosDB Nano is a self-hosted relational database that pairs standard SQL, with joins and multi-statement transactions, with backend services in the same binary: PostgREST-style REST (its table routes are a known issue in the current release), email and OAuth sign-in, and a realtime WebSocket (known issue: realtime events are not delivered in the current release; tracked by the Nano team). It runs embedded or as a server on infrastructure you control. Licensed Apache 2.0.
Last updated
Choose HeliosDB Nano when your data is relational and you want standard SQL with joins and multi-table transactions, self-hosted under Apache 2.0 with REST, auth and a realtime WebSocket in the same binary; keep Firebase when you need live listeners on every write today, want Google to run everything, first-class mobile SDKs with offline sync, push messaging, hosting or analytics.
Firebase is Google's Backend-as-a-Service platform built around a proprietary NoSQL document database (Firestore). HeliosDB Nano gives you a relational SQL database with BaaS conveniences — auth, a REST API and a realtime WebSocket (known issue: realtime events are not delivered in the current release; tracked by the Nano team) — without vendor lock-in or cloud dependency.
| Feature | Firebase | HeliosDB Nano |
|---|---|---|
| Data Model | NoSQL (Firestore documents) | Relational SQL + JSONB |
| Query Language | Proprietary SDK queries | Standard SQL (PostgreSQL dialect) |
| Hosting | Google Cloud only | Self-hosted (any server) |
| Auth | Firebase Auth (email, OAuth, phone) | Built-in (email, OAuth, JWT) |
| Realtime | Firestore onSnapshot | WebSocket in the Supabase message shape (Known issue: realtime events are not delivered in the current release; tracked by the Nano team) |
| Server Logic | Cloud Functions (Node.js) | SQL functions over the PostgreSQL wire (the REST rpc route is a known issue in the current release; PL/pgSQL control flow planned) |
| REST API | Firebase REST API | PostgREST-style (/rest/v1 table routes a known issue in the current release) |
| File Storage | Cloud Storage for Firebase | Planned (buckets and signed URLs); database data persists in a data directory |
| Vector Search | Firebase Extensions (preview) | Native HNSW + Product Quantization (default build) |
| Joins | Not supported (denormalize) | Full SQL JOINs |
| Aggregation | Limited (count, sum, avg) | Full SQL (GROUP BY, HAVING, window functions) |
| Transactions | Limited (document-level) | ACID, multi-table (independent sessions in server mode) |
| Branching | N/A | Built-in copy-on-write |
| Time Travel | N/A | Built-in (AS OF TIMESTAMP, within retention) |
| Encryption | Google-managed keys | AES-256-GCM with your key, off until configured |
| Open Source | SDKs only (backend proprietary) | Apache 2.0 (full engine) |
| Vendor Lock-In | High (Google Cloud) | None (self-hosted) |
| Offline Support | Firestore offline cache | Full database (embedded mode) |
| Pricing | Free tier + pay-per-read/write | Free to self-host (Apache 2.0); Nano Cloud from $0/mo |
Firebase forces you into a document model. Simple queries become complex workarounds when your data has relationships:
// Firebase: Get all orders for a user, with product details
// Requires multiple queries and client-side joins
const ordersSnap = await db.collection('orders')
.where('userId', '==', userId)
.get()
const productIds = ordersSnap.docs.map(d => d.data().productId)
// Firestore 'in' queries limited to 30 items
const chunks = chunkArray(productIds, 30)
const products = []
for (const chunk of chunks) {
const snap = await db.collection('products')
.where('id', 'in', chunk)
.get()
products.push(...snap.docs.map(d => d.data()))
}
// Manual join on the client
const result = ordersSnap.docs.map(order => ({
...order.data(),
product: products.find(p => p.id === order.data().productId)
}))
-- HeliosDB Nano: one query, server-side
SELECT o.*, p.name AS product_name, p.price
FROM orders o
JOIN products p ON o.product_id = p.id
WHERE o.user_id = $1
ORDER BY o.created_at DESC;
Firebase locks you into Google's proprietary APIs. Migrating away means rewriting your entire data layer. HeliosDB Nano uses standard SQL and the PostgreSQL and MySQL wire protocols, so common database tools connect:
| Aspect | Firebase | HeliosDB Nano |
|---|---|---|
| Query language | Proprietary SDK | Standard SQL |
| Data export | Firebase CLI (JSON) | heliosdb-nano dump; SQL from any client |
| Migration path | Rewrite data layer | Standard SQL over PostgreSQL or MySQL clients |
| Compatible tools | Firebase ecosystem only | psql, DBeaver, pgAdmin, most PostgreSQL drivers and ORMs |
| Hosting options | Google Cloud only | Any Linux, macOS or Windows server you control |
-- Complex analytics impossible in Firestore
WITH monthly_revenue AS (
SELECT
DATE_TRUNC('month', created_at) AS month,
SUM(total) AS revenue,
COUNT(*) AS order_count
FROM orders
WHERE status = 'completed'
GROUP BY DATE_TRUNC('month', created_at)
)
SELECT
month,
revenue,
order_count,
LAG(revenue) OVER (ORDER BY month) AS prev_month,
ROUND((revenue - LAG(revenue) OVER (ORDER BY month))
/ LAG(revenue) OVER (ORDER BY month) * 100, 1) AS growth_pct
FROM monthly_revenue
ORDER BY month DESC;
Firebase transactions are limited to document-level operations. HeliosDB Nano supports multi-table ACID transactions with savepoints. Independent concurrent transactions need server mode (the embedded API has one transaction slot per process), and concurrent autocommit read-modify-write updates of one row can lose increments today (concurrency and transactions · known limitations):
BEGIN;
SAVEPOINT before_transfer;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
-- Verify no negative balance
SELECT balance FROM accounts WHERE id = 1;
-- If negative: ROLLBACK TO SAVEPOINT before_transfer;
INSERT INTO transfers (from_id, to_id, amount, created_at)
VALUES (1, 2, 500, NOW());
COMMIT;
A branch is a copy-on-write clone of the whole database. Merges are last-writer-wins with no conflict detection, so re-apply validated SQL to main when anything else may have changed (merging branches):
-- Test schema migrations safely
CREATE DATABASE BRANCH feature_v2 FROM main;
USE BRANCH feature_v2;
ALTER TABLE users ADD COLUMN tier TEXT DEFAULT 'free';
ALTER TABLE orders ADD COLUMN discount DECIMAL(5,2);
-- Run the test suite against the branch, then discard it
-- and re-apply the validated SQL to main
USE BRANCH main;
DROP DATABASE BRANCH feature_v2;
Firebase runs server logic in Cloud Functions. HeliosDB Nano runs SQL functions inside the database. Its REST API publishes them at /rest/v1/rpc/{function} (REST API tutorial), but the /rest/v1 routes are a known issue in the current release, so call functions over the PostgreSQL wire until a fixed release. Nano runs plain-SQL DO blocks and simple SQL/plpgsql functions; PL/pgSQL control flow and trigger bodies are planned, so keep branching logic in your application (PL/pgSQL compatibility).
-- A SQL function, no separate deployment
CREATE FUNCTION discount(amount NUMERIC, pct NUMERIC) RETURNS NUMERIC
LANGUAGE SQL AS $$
SELECT amount * (1 - pct / 100);
$$;
# Call it from any PostgreSQL client
psql -h 127.0.0.1 -p 5432 -U postgres -c "SELECT discount(100, 15);"
-- Semantic search built into the database
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title TEXT,
body TEXT,
embedding VECTOR(768)
);
-- Find similar articles
SELECT title, embedding <=> $1::vector(768) AS similarity
FROM articles
ORDER BY similarity
LIMIT 5;
Firebase charges per read, write, and data stored. Costs grow unpredictably with traffic:
| Usage Level | Firebase (est.) | HeliosDB Nano |
|---|---|---|
| Hobby (10K reads/day) | Free tier | Free (self-hosted) |
| Startup (1M reads/day) | $50-150/mo | Free (self-hosted) |
| Growth (10M reads/day) | $500-2,000/mo | Free (self-hosted) |
| Scale (100M reads/day) | $5,000-20,000/mo | Free (self-hosted) |
With self-hosted HeliosDB Nano the software is free under Apache 2.0 and your cost is the infrastructure you run it on; size it by measuring your own workload. Managed Nano Cloud plans are listed on the pricing page.
Firebase might be a better fit if you need:
CREATE POLICY and enforcement for REST and wire clients are planned, so a server deployment must enforce access in the application. Deployment modes · Security hardeningBEFORE INSERT row rewrites) and PL/pgSQL control flow are planned; today Nano runs plain-SQL DO blocks and simple SQL/plpgsql functions. Known limitations · PL/pgSQL compatibility@heliosdb/client is built from the HeliosDB SDKs source. TypeScript SDK--password is visible in the process list. Known limitations: securityThe Nano documentation has no Firestore converter. Export your collections to JSON with Google's tooling, map each collection to a table (step 2), then load the rows through any PostgreSQL client. The REST API's JSON-array bulk insert (REST API tutorial) depends on the /rest/v1 table routes, a known issue in the current release, so load over the PostgreSQL wire:
# Bulk-insert converted rows over the PostgreSQL wire
import psycopg2
rows = [("uid-1", "ada@example.com"), ("uid-2", "lin@example.com")]
conn = psycopg2.connect("host=127.0.0.1 port=5432 dbname=app user=postgres")
with conn, conn.cursor() as cur:
cur.executemany(
"INSERT INTO users (firebase_uid, email) VALUES (%s, %s)", rows
)
-- Firestore collection: users/{userId}
-- becomes a SQL table with proper types and constraints
CREATE TABLE users (
id SERIAL PRIMARY KEY,
firebase_uid TEXT UNIQUE,
email TEXT NOT NULL,
display_name TEXT,
photo_url TEXT,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Nested sub-collections become related tables with foreign keys
CREATE TABLE user_settings (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id) ON DELETE CASCADE,
theme TEXT DEFAULT 'light',
notifications BOOLEAN DEFAULT true,
preferences JSONB DEFAULT '{}'
);
// Before: Firebase
import { getFirestore, collection, query, where, getDocs } from 'firebase/firestore'
const db = getFirestore()
const q = query(collection(db, 'users'), where('active', '==', true))
const snap = await getDocs(q)
const users = snap.docs.map(d => ({ id: d.id, ...d.data() }))
// After: HeliosDB Nano over the PostgreSQL wire (node-postgres)
import pg from 'pg'
const db = new pg.Pool({ host: 'localhost', port: 5432, database: 'app' })
const { rows: users } = await db.query('SELECT * FROM users WHERE active = $1', [true])
// @heliosdb/client (built from source, not npm) offers a fluent REST API,
// but its table queries use the /rest/v1 routes, a known issue in the current release
HeliosDB Nano, built from source with these features, adds CREATE EXTENSION hdb_code for SQL-callable LSP, the WITH CONTEXT clause for grounded RAG, eight ingestion adapters (incl. Docling-backed PDF / Office / audio / image), an in-process embedder, and a native MCP server reachable from Claude Code, Cursor, Continue, Codex, and Aider. Equivalents for HeliosDB Lite and Full are planned. Learn more →
Get started with HeliosDB in minutes. Open source, free to use.