Firebase is Google's Backend-as-a-Service platform built around a proprietary NoSQL document database (Firestore). HeliosDB Nano gives you a full relational SQL database with the same BaaS conveniences — auth, REST API, realtime — without vendor lock-in or cloud dependency.


Quick Comparison

Feature Firebase HeliosDB Nano
Data ModelNoSQL (Firestore documents)Relational SQL + JSONB
Query LanguageProprietary SDK queriesStandard SQL (PostgreSQL dialect)
HostingGoogle Cloud onlySelf-hosted (any server)
AuthFirebase Auth (email, OAuth, phone)Built-in (email, OAuth, JWT)
RealtimeFirestore onSnapshotWebSocket (postgres_changes)
Server LogicCloud Functions (Node.js)PL/pgSQL stored procedures
REST APIFirebase REST APIPostgREST-compatible (auto-generated)
File StorageCloud Storage for FirebaseIn-memory (disk persistence planned)
Vector SearchFirebase Extensions (preview)Native HNSW (production-ready)
JoinsNot supported (denormalize)Full SQL JOINs
AggregationLimited (count, sum, avg)Full SQL (GROUP BY, HAVING, window functions)
TransactionsLimited (document-level)Full ACID (multi-table)
BranchingN/ABuilt-in (zero-cost, COW)
Time TravelN/ABuilt-in (AS OF TIMESTAMP)
EncryptionGoogle-managed keysAES-256-GCM TDE (your keys)
Open SourceSDKs only (backend proprietary)Source available (SSPL-1.0)
Vendor Lock-InHigh (Google Cloud)None (self-hosted)
Offline SupportFirestore offline cacheFull database (embedded mode)
PricingFree tier + pay-per-read/writeFree forever (self-hosted)

SQL vs NoSQL: Why It Matters

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;

No Vendor Lock-In

Firebase locks you into Google's proprietary APIs. Migrating away means rewriting your entire data layer. HeliosDB uses standard SQL and wire protocols compatible with thousands of tools:

Aspect Firebase HeliosDB Nano
Query languageProprietary SDKStandard SQL
Data exportFirebase CLI (JSON)pg_dump, mysqldump, CSV
Migration pathRewrite data layerChange connection string
Compatible toolsFirebase ecosystem onlypsql, DBeaver, pgAdmin, any ORM
Hosting optionsGoogle Cloud onlyAny server, VPS, Raspberry Pi

What HeliosDB Adds Beyond Firebase

1. Real SQL with JOINs, CTEs, and Window Functions

-- 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;

2. Full ACID Transactions

Firebase transactions are limited to document-level operations. HeliosDB supports multi-table ACID transactions with savepoints:

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;

3. Database Branching

-- Test schema migrations safely
CREATE 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 test suite against branch
-- If everything passes:
MERGE BRANCH feature_v2 INTO main;

4. Stored Procedures (Server-Side Logic)

Firebase requires Cloud Functions (external Node.js runtime with cold starts). HeliosDB runs logic inside the database:

-- Server-side logic, no cold starts, no separate deployment
CREATE FUNCTION process_order(order_id INT) RETURNS VOID AS $$
BEGIN
    UPDATE orders SET status = 'processing' WHERE id = order_id;
    UPDATE inventory SET quantity = quantity - (
        SELECT quantity FROM order_items WHERE order_id = order_id
    );
    INSERT INTO audit_log (action, entity_id, timestamp)
    VALUES ('order_processed', order_id, NOW());
END;
$$ LANGUAGE plpgsql;

5. Native Vector Search

-- 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 AS similarity
FROM articles
ORDER BY similarity
LIMIT 5;

Cost Comparison

Firebase charges per read, write, and data stored. Costs grow unpredictably with traffic:

Usage Level Firebase (est.) HeliosDB Nano
Hobby (10K reads/day)Free tierFree (self-hosted)
Startup (1M reads/day)$50-150/moFree (self-hosted)
Growth (10M reads/day)$500-2,000/moFree (self-hosted)
Scale (100M reads/day)$5,000-20,000/moFree (self-hosted)

With HeliosDB Nano, your only cost is the server you run it on. A $5/month VPS can handle millions of queries per day.


When to Choose Firebase

Firebase might be a better fit if you need:

  • Zero ops -- Google manages everything, no server to maintain
  • Mobile SDKs -- first-class iOS/Android/Flutter SDKs with offline sync
  • Push notifications -- Firebase Cloud Messaging built in
  • Hosting + CDN -- Firebase Hosting for static sites
  • Analytics -- Google Analytics integration
  • Simple data model -- document-oriented data without complex relationships

When to Choose HeliosDB Nano

  • Relational data -- JOINs, foreign keys, constraints, transactions
  • No vendor lock-in -- standard SQL, portable data, any hosting
  • Self-hosted / data sovereignty -- your data on your server
  • Predictable costs -- no per-read/write billing surprises
  • Complex queries -- CTEs, window functions, aggregations, subqueries
  • Database branching -- safe schema migrations and testing
  • Time-travel queries -- audit, compliance, debugging
  • MySQL applications -- WordPress, Laravel, legacy systems
  • Edge / embedded -- 47 MB binary, 30 MB RAM, 10ms startup

Migration from Firebase

1. Export Your Firestore Data

# Export Firestore to JSON
firebase firestore:export gs://your-bucket/export

# Convert to SQL (using heliosdb-migrate tool)
heliosdb-migrate --from firestore --input ./export --output schema.sql

2. Map Document Collections to Tables

-- 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 '{}'
);

3. Replace Firebase SDK Calls

// 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 (REST API)
import { createClient } from '@heliosdb/client'
const db = createClient('http://localhost:8080', 'your-anon-key')
const { data: users } = await db.from('users').select('*').eq('active', true)

Ready to try HeliosDB?

Get started with HeliosDB in minutes. Open source, free to use.

Get Started Contact Sales