NEW FEATURE

AxioDBCloud

Remote Database Access Made Simple

Deploy AxioDB in Docker or Cloud. Connect from anywhere with the same API you already know. Zero code changes, production-ready TCP protocol, automatic reconnection.

Why AxioDBCloud?

Zero Code Changes

Use the exact same API as embedded AxioDB. Just change from new AxioDB() to new AxioDBCloud()

Deploy Anywhere

Docker, AWS, Azure, Google Cloud, DigitalOcean, or your own servers. One instance, unlimited clients.

Auto-Reconnect

Built-in exponential backoff reconnection. Up to 10 retry attempts. Your app stays resilient.

Production Ready

1000+ concurrent connections, heartbeat monitoring, request correlation, connection pooling.

Server Setup

Option 1: Docker (Recommended)

The easiest way to deploy AxioDB with TCP access. Full instructions — simpledocker runquick start, then advanced env vars, volumes, and Compose — live on the dedicated Docker page:

Docker Deployment Guide

Option 2: Node.js Application

Using this config, you can expose an AxioDB instance running inside one service (Service A) so it can be reached over TCP from another service (Service B) using the AxioDBCloud client — no shared filesystem, no HTTP layer, just a direct TCP connection between processes:

javascript
1const { AxioDB } = require('axiodb');
2
3// Service A: the process that owns the data, exposed for other services to reach
4const db = new AxioDB({
5 GUI: false, // GUI (optional)
6 RootName: 'MyDatabase', // Root database name
7 CustomPath: './data', // Data directory
8 TCP: true // Enable TCP server
9});
10
11// Server automatically starts on port 27019
12console.log('AxioDB TCP Server running on port 27019');

Default Port: TCP server listens on port 27019 (HTTP GUI uses 27018). Service B then connects with new AxioDBCloud("axiodb://service-a-host:27019") — see Client Usage below.

Client Usage

Basic Connection

javascript
1const { AxioDBCloud } = require('axiodb');
2
3// Connect to remote AxioDB server
4const client = new AxioDBCloud("axiodb://localhost:27019");
5
6// Establish connection
7await client.connect();
8
9// Use exactly like embedded AxioDB!
10const db = await client.createDB("ProductionDB");
11const users = await db.createCollection("Users");
12
13// All operations work identically
14await users.insert({ name: "Alice", email: "[email protected]" });
15
16const results = await users.query({ name: "Alice" })
17 .Limit(10)
18 .Skip(0)
19 .Sort({ createdAt: -1 })
20 .exec();
21
22console.log(results);
23
24// Disconnect when done
25await client.disconnect();

Connection String Format

axiodb://[host]:[port]
  • • Local: axiodb://localhost:27019
  • • Remote: axiodb://192.168.1.100:27019
  • • Cloud: axiodb://mydb.example.com:27019

Advanced Options

javascript
1const client = new AxioDBCloud("axiodb://localhost:27019", {
2 timeout: 30000, // Request timeout (ms)
3 reconnectAttempts: 10, // Max reconnect attempts
4 reconnectDelay: 1000, // Initial delay (ms)
5 heartbeatInterval: 30000, // Heartbeat every 30s
6 maxPoolSize: 10, // Concurrent connections in the pool (default: 10)
7 username: 'admin', // Only needed if the server has TCPAuth: true
8 password: 'admin',
9});

maxPoolSize mirrors MongoDB's driver option of the same name. AxioDBCloud opens this many concurrent TCP connections to the server and routes each command to whichever connected member currently has the fewest in-flight requests (least-busy), so a burst of concurrent requests isn't serialized over a single socket, and a slow command on one connection doesn't queue new work behind it while other members sit idle. Each pooled connection reconnects and re-authenticates independently, so one dropped connection never blocks commands routed to the others.

Each pool member is a socket, and the server holds one socket per connected client - both count against the OS's open-file-descriptor limit (ulimit -n, often 1024 by default on Linux). At the default pool size that's enough for roughly 100 clients before the server starts refusing new connections. If you're deploying towards the 1,000+ concurrent connections the server supports, raise the limit (e.g. ulimit -n 65536, or docker run --ulimit nofile=65536:65536) rather than raising maxPoolSize per client.

The server also caps concurrent connections at 100 per remote IP, independent of the global 1,000-connection budget - so a single misbehaving or malicious client can't claim the entire pool of server connections for itself. This is checked at connect time, before authentication, and rejects the extra connection with a 429 ("Too many concurrent connections from this IP address"). A single client at the default maxPoolSize: 10 is nowhere near this limit.

If maxPoolSize asks for more connections than the server allows (from the per-IP cap above, or any other reason a handful of pool members fail),connect() doesn't reject outright - it resolves as long as at least one pool member connected, and emits a poolDegraded event so the app knows it's running with fewer connections than requested instead of failing (or silently under capacity):

javascript
1client.on('poolDegraded', ({ requested, connected, failed, errors }) => {
2 console.warn(`Pool came up smaller than requested: ${connected}/${requested} connected, ${failed} failed`);
3 console.warn(errors[0].message); // e.g. "Too many concurrent connections from this IP address"
4});
5
6await client.connect(); // resolves even if some pool members were rejected

The one exception is the very first connection in the pool - if that one fails,connect() still rejects entirely, since it's the signal that the server is reachable and credentials are valid at all.

The 100-per-IP cap only bounds concurrent connections - by itself it wouldn't stop an attacker who never holds more than a few sockets open but rapidly opens and drops them, since each attempt still costs a TCP handshake and an accept/reject cycle. A separate per-IP rate limiter tracks connection attempts (successful or rejected, either counts) in a trailing 10-second window; once an IP crosses 300 attempts, every new connection from it is rejected with a 429 for the next 30 seconds. A normal client - even one repeatedly reconnecting a full maxPoolSize: 10 pool - is nowhere near this threshold.

TCP Authentication (NEW!)

TCP connections are unauthenticated by default (unchanged from before). Opt in with TCPAuth: true to require a username/password on every connection - it reuses the exact same accounts and roles as the GUI Control Server's RBAC system, so there's only one set of credentials to manage.

Server

javascript
1const db = new AxioDB({
2 TCP: true,
3 TCPAuth: true, // Require authentication on every TCP connection
4 RootName: 'MyDatabase',
5 CustomPath: './data',
6});

Client

javascript
1// Pass credentials in the constructor options - connect() authenticates automatically
2const client = new AxioDBCloud("axiodb://localhost:27019", {
3 username: 'admin',
4 password: 'admin',
5});
6await client.connect();
7
8console.log(client.authenticatedUser);
9// { username: 'admin', role: 'Super Admin', mustChangePassword: false }
10
11// Or authenticate after connecting (e.g. credentials supplied at runtime)
12const client2 = new AxioDBCloud("axiodb://localhost:27019");
13await client2.connect();
14await client2.login('admin', 'admin');

What's enforced

  • • Every command except PING/DISCONNECT/AUTHENTICATE requires a prior successful login on that connection
  • • Same role permissions as the GUI, checked per command (e.g. a View-role user gets 403 on CREATE_DB)
  • • Shared per-IP login rate limiter with the GUI: 5 failed attempts in 15 minutes locks that IP out for 15 minutes (429)
  • • Accounts still needing their forced password change are rejected outright (403) - complete it via the GUI first
  • • A password reset, role change, or deletion via the GUI immediately forces an already-open TCP connection to re-authenticate

Known limitations

  • • No TCP command exists yet to change a password - that must go through the GUI

TLS Encryption (NEW!)

By default, the TCP protocol is plaintext - anyone who can capture network traffic between client and server (e.g. Wireshark on a shared network) can read your data and, if TCPAuth is on, your password. TLS fixes this. It's off by default - nothing here is required, and existing plaintext deployments keep working exactly as before unless you turn it on.

You must provide your own certificate + key. AxioDB never generates one for you - that's a security decision only you can make (a real cert from a CA, or a self-signed one for local/private use).

Step 1 - Get a cert + key

For local/dev/private use, generate a self-signed one (one-time, takes a second):

bash
1openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"

This creates two files, cert.pem and key.pem, in your current folder. For a real production deployment reachable from the internet, use a cert from a real CA (Let's Encrypt, your org's CA, your cloud provider's managed cert) instead - the rest of the setup is identical either way.

Step 2 - Point the server at them

javascript
1const { AxioDB } = require('axiodb');
2const db = new AxioDB({
3 TCP: true,
4 TLS: true,
5 TLSCertPath: './cert.pem', // path to the file from step 1
6 TLSKeyPath: './key.pem',
7});

If TLS: true but either path is missing or unreadable, AxioDB throws immediately at startup - it never silently falls back to plaintext.

Step 3 - Point the client at the same cert

Only needed because it's self-signed - a real CA-issued cert wouldn't need this step, the same way your browser trusts https:// sites without extra setup:

javascript
1const { AxioDBCloud } = require('axiodb');
2const client = new AxioDBCloud("axiodb://localhost:27019", {
3 tls: true,
4 tlsCAPath: './cert.pem', // same cert.pem from step 1 - proves this server is the real one
5});
6await client.connect();

Without tlsCAPath, the client refuses to connect to a self-signed server by default (tlsRejectUnauthorized defaults to true) - this is intentional, the same protection that stops a browser from silently trusting a fake https:// site. Only set tlsRejectUnauthorized: false for local/dev testing, never in production, since it turns that protection off entirely.

Running this in Docker?

The cert/key files need to get into the container. The simplest way to think about it: your cert files live on your real machine; a Docker bind mount (-v) makes a folder from your machine visible inside the container at whatever path you choose, and you point the env vars at that in-container path, not your real machine's path:

bash
1# cert.pem and key.pem are really at /home/you/mycerts/ on your machine.
2# "/certs" below is just a name we're choosing for where they'll appear inside the container.
3docker run -d --name axiodb-server \
4 -p 27018:27018 -p 27019:27019 \
5 -v /home/you/mycerts:/certs:ro \
6 -e AXIODB_TLS=true \
7 -e AXIODB_TLS_CERT_PATH=/certs/cert.pem \
8 -e AXIODB_TLS_KEY_PATH=/certs/key.pem \
9 theankansaha/axiodb

The rule: the AXIODB_TLS_CERT_PATH value must always match the right-hand side of the -v mount (/certs/...), never the real path on your machine - the container can't see your machine's filesystem directly, only whatever you've explicitly mounted into it.

Complete API Examples

CRUD Operations

javascript
1// Insert single document
2await users.insert({ name: "Bob", age: 30 });
3
4// Insert multiple documents
5await users.insertMany([
6 { name: "Charlie", age: 25 },
7 { name: "Diana", age: 28 }
8]);
9
10// Query documents
11const adults = await users.query({ age: { $gte: 18 } })
12 .Limit(10)
13 .Sort({ age: -1 })
14 .exec();
15
16// Update document
17await users.update({ name: "Bob" }).UpdateOne({ age: 31 });
18
19// Delete document
20await users.delete({ name: "Charlie" }).deleteOne();
21
22// Aggregation
23const stats = await users.aggregate([
24 { $match: { age: { $gte: 25 } } },
25 { $group: { _id: null, avgAge: { $avg: "$age" } } }
26]).exec();

Real-World Example: E-commerce App

javascript
1const { AxioDBCloud } = require('axiodb');
2
3async function main() {
4 // Connect to production database
5 const client = new AxioDBCloud("axiodb://prod.example.com:27019");
6 await client.connect();
7
8 const db = await client.createDB("EcommerceDB");
9 const products = await db.createCollection("Products");
10 const orders = await db.createCollection("Orders");
11
12 // Add new product
13 await products.insert({
14 sku: "LAPTOP-001",
15 name: "Gaming Laptop",
16 price: 1299.99,
17 stock: 15,
18 category: "Electronics"
19 });
20
21 // Get low stock products
22 const lowStock = await products.query({ stock: { $lt: 10 } })
23 .Sort({ stock: 1 })
24 .exec();
25
26 console.log("Low stock products:", lowStock.data.documents);
27
28 // Create order
29 await orders.insert({
30 orderId: "ORD-12345",
31 customerId: "USER-001",
32 items: [{ sku: "LAPTOP-001", quantity: 1 }],
33 total: 1299.99,
34 status: "pending"
35 });
36
37 // Get today's orders
38 const today = new Date().toISOString().split('T')[0];
39 const todayOrders = await orders.query({
40 createdAt: { $regex: today }
41 }).exec();
42
43 console.log("Today's orders:", todayOrders.data.documents.length);
44
45 await client.disconnect();
46}
47
48main().catch(console.error);

Features & Capabilities

35+ Commands

Full CRUD, aggregation, indexing support

Optional Auth (NEW!)

Shared RBAC with the GUI, per-IP rate limiting

Auto-Reconnect

Exponential backoff with 10 retry attempts

Heartbeat

PING/PONG every 30 seconds

Connection Pool

1000+ concurrent connections

Fast Protocol

Binary JSON with 4-byte length prefix

TypeScript

Full type definitions included

Perfect For

Microservices

Share one AxioDB instance across multiple services

Desktop Apps

Electron apps connecting to local or remote database

Cloud Deployments

Deploy to AWS, Azure, Google Cloud, DigitalOcean

Ready to Get Started?

Deploy AxioDB in minutes and start connecting from anywhere.