jaydb Documentation
Ship apps with no backend at all. Your app is a folder of static files; jaydb is both the login and the database, reached straight from the browser.
Introduction
jaydb removes the backend from app development. An app ships as static files, and jaydb provides the two things those files cannot provide themselves: real per-user sign-in and a shared database. There is no server of your own to run — not a serverless function, not a BaaS SDK, no API tier, no auth service, no session store.
What normally sits between a static frontend and its data — an auth service, an API tier, a session store, an ORM, a connection pool, and a deploy pipeline for all of it — is not made cheaper here. It is deleted. Each end user signs in with their own identity through a per-tenant OIDC issuer, so the browser talks to the data plane directly with a token scoped to that user, and nothing confidential ships to the front end.
Serverless functions still boot a server per request — one that you write, deploy, and version. jaydb removes that layer entirely. The only always-on system is jaydb, which you do not operate.
Two ways to build
Both talk to the same data plane. The difference is whether a server of yours is involved at all.
| Shape | Credential | When |
|---|---|---|
| Frontend-only (the default) | Authorization: Bearer <jwt> |
Static files on any host. Users sign in with OIDC + PKCE; the browser gets its own token, scoped to that user. |
| Server-side integration | X-JayDB-API-Key |
A backend, script, or job holds a long-lived secret. Optional — never required to start. |
See Authentication for both flows in full.
Underneath: the database itself
jaydb is a high-performance document database written in Go. It uses AWS S3 (or any S3-compatible object storage such as Cloudflare R2, MinIO, or Wasabi) as its durability layer, with sub-millisecond in-memory sharded caching, atomic Compare-and-Swap (CAS) locking, and singleflight read coalescing. One key holds one JSON document; you read it, write it, or compare-and-swap it. That engine is open source and MIT licensed, and can be self-hosted.
Every API action is plain HTTP with standard headers — no client SDK, no connection string. That also makes jaydb a natural target when an AI agent scaffolds an app that needs shared state: a namespace is created on first write, so there is no provisioning turn to burn. Agents can read the whole surface from one fetch at /api.md or /llms.txt.
5-Minute Quickstart
You can interact with JayDB Cloud using standard HTTP requests (with curl or native fetch), or use the official zero-dependency Frontend SDK (@jaydb/cloud) for automated OIDC token management and typed CAS primitives. For a full, runnable application demonstrating user sign-in and real-time synchronization, see the Kanban Demo App below.
1. Write a document
Write any JSON document to a hierarchical path. If the namespace does not exist, it is created implicitly on first write.
curl -X PUT https://acme.jaydb.com/v1/n/app/docs/users/101 \
-H "X-JayDB-API-Key: $JAYDB_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "role": "admin", "plan": "pro"}'
const res = await fetch('https://acme.jaydb.com/v1/n/app/docs/users/101', {
method: 'PUT',
headers: {
'X-JayDB-API-Key': process.env.JAYDB_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'Alice', role: 'admin', plan: 'pro' }),
});
const meta = await res.json();
console.log('Saved with ETag:', meta.etag);
import os, requests
res = requests.put(
"https://acme.jaydb.com/v1/n/app/docs/users/101",
headers={"X-JayDB-API-Key": os.environ["JAYDB_KEY"]},
json={"name": "Alice", "role": "admin", "plan": "pro"}
)
meta = res.json()
print(f"Saved with ETag: {meta['etag']}")
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{"name":"Alice","role":"admin","plan":"pro"}`)
req, _ := http.NewRequest("PUT", "https://acme.jaydb.com/v1/n/app/docs/users/101", bytes.NewReader(body))
req.Header.Set("X-JayDB-API-Key", os.Getenv("JAYDB_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}
2. Read a document
Retrieve the document and its current version ETag header:
curl -i https://acme.jaydb.com/v1/n/app/docs/users/101 \
-H "X-JayDB-API-Key: $JAYDB_KEY"
const res = await fetch('https://acme.jaydb.com/v1/n/app/docs/users/101', {
headers: { 'X-JayDB-API-Key': process.env.JAYDB_KEY },
});
const etag = res.headers.get('ETag');
const user = await res.json();
console.log(user, 'ETag:', etag);
res = requests.get(
"https://acme.jaydb.com/v1/n/app/docs/users/101",
headers={"X-JayDB-API-Key": os.environ["JAYDB_KEY"]}
)
etag = res.headers.get("ETag")
doc = res.json()
print(doc, "ETag:", etag)
req, _ := http.NewRequest("GET", "https://acme.jaydb.com/v1/n/app/docs/users/101", nil)
req.Header.Set("X-JayDB-API-Key", os.Getenv("JAYDB_KEY"))
resp, _ := http.DefaultClient.Do(req)
etag := resp.Header.Get("ETag")
defer resp.Body.Close()
Frontend SDK (@jaydb/cloud)
While JayDB Cloud can be queried directly with native fetch() or curl, we provide an official, zero-dependency client SDK—@jaydb/cloud. It gives frontend applications typed document access, OIDC + PKCE browser authentication, automatic token refresh, optimistic concurrency control (CAS), and structured error handling in a lightweight bundle (~12 KB minified).
Visit the standalone Interactive SDK Documentation & Playground ↗ or view the source on GitHub: jaydb-cloud/jaydb-cloud-sdk ↗.
Installation
Install from npm or use a native browser <script type="importmap"> without any bundler or build step:
npm install @jaydb/cloud
<script type="importmap">
{
"imports": {
"@jaydb/cloud": "https://jaydb-cloud.github.io/jaydb-cloud-sdk/jaydb-cloud.esm.min.js"
}
}
</script>
1. Authentication with OIDC + PKCE
The Auth class encapsulates the entire OAuth 2.0 / OIDC Authorization Code Flow with PKCE. Tokens and cryptographic verifiers are securely kept in client storage (defaults to sessionStorage) with zero client secrets in browser code:
import { Auth } from '@jaydb/cloud';
const auth = new Auth({
tenant: 'acme', // acme.jaydb.com
clientId: 'app_kanban', // Registered public PKCE client
redirectUri: window.location.origin + '/callback',
scopes: ['openid', 'profile', 'email'],
});
// Initiate login redirect if not signed in
if (!auth.isSignedIn()) {
auth.signIn();
}
// On callback page: exchange authorization code for user token
await auth.handleCallback();
const user = auth.getUser();
console.log('Signed in as:', user.email);
2. Initializing JayDB Client
Pass the auth instance directly into JayDB. Every document operation automatically resolves a valid Bearer token (coalescing requests and refreshing silently in the background):
import { JayDB, Auth } from '@jaydb/cloud';
const auth = new Auth({ tenant: 'acme', clientId: 'app_kanban' });
const db = new JayDB({
tenant: 'acme',
namespace: 'app',
auth, // or custom getToken: async () => accessToken
});
3. CRUD Operations & CAS Optimistic Concurrency
All write operations natively support compare-and-swap (CAS) via { ifMatch: etag } and create-only locks via { createOnly: true }. When a conflict occurs, the SDK throws a structured ConflictError:
import { ConflictError, NotFoundError } from '@jaydb/cloud';
// 1. Create a document safely (fails if key already exists)
const created = await db.put('boards/main', { title: 'Kanban' }, { createOnly: true });
console.log('Created with ETag:', created.etag);
// 2. Read document
const doc = await db.get('boards/main');
if (!doc) throw new NotFoundError('board missing');
// 3. Update with optimistic concurrency control
try {
const updated = await db.put(
'boards/main',
{ ...doc.data, title: 'Sprint Board' },
{ ifMatch: doc.etag } // Guarantees no overwrite if another user modified it
);
} catch (err) {
if (err instanceof ConflictError) {
console.warn('Conflict detected! Re-fetch latest and retry.');
}
}
// 4. List documents under a prefix
const { keys, prefixes } = await db.list({ prefix: 'boards/' });
// 5. Delete with version guard
await db.delete('boards/main', { ifMatch: doc.etag });
Error Hierarchy
The SDK provides explicit error types so application logic can cleanly distinguish between network, precondition, and auth issues:
JayDBError: Base error class withstatus,statusText, and response details.ConflictError: Thrown on HTTP 412 (Precondition Failed) when anifMatchorcreateOnlycheck fails.NotFoundError: Thrown or returned on HTTP 404.AuthError: Thrown on HTTP 401 or 403 authorization failures.
Example: Kanban Demo App
Looking for a complete, production-ready usage example? The JayDB Kanban Demo is a real-time, multi-user Kanban board built with zero backend servers and powered by the @jaydb/cloud SDK. It showcases how a static frontend uses JayDB Cloud for both browser login and direct document storage.
Open jaydb-cloud.github.io/jaydb-kanban-demo in two browser windows side-by-side to watch cards, moves, edits, and active presence sync in real time.
What the demo illustrates
- Zero backend servers: Pure static frontend (HTML, CSS, vanilla JS) deployed on GitHub Pages. No Node.js, serverless lambdas, or backend proxies are involved.
- Browser sign-in with OIDC + PKCE: Managed via
Authfrom@jaydb/cloud. Users authenticate via Google or GitHub against the tenant's OIDC issuer. Scoped access tokens are stored insessionStorageand refreshed silently. - Direct browser-to-database requests: Every card creation, update, and deletion is performed directly through
JayDBclient targetinghttps://{tenant}.jaydb.com/v1/n/{namespace}/docs/{key}with Bearer tokens. - Optimistic concurrency (CAS): Moving cards or editing text uses
db.put(key, data, { ifMatch: etag }). When two users modify a card simultaneously, the write throws a typedConflictError(HTTP 412), prompting the store to re-read the winning version and replay the change conflict-free. - Presence and live synchronization: Instead of heavyweight WebSocket servers, the client queries key prefixes with
db.list({ prefix: 'cards/' })and polls at a light cadence, diffing ETags to re-render only modified items. - Zero-build distribution: Native ES module import via
<script type="importmap">resolving@jaydb/clouddirectly from the CDN with no build tools or package managers required.
import { ConflictError } from '@jaydb/cloud';
// Read-modify-write with bounded retry using CAS primitives
async function mutateCard(id, mutate, { retries = 4 } = {}) {
let record = cards.get(id) ?? (await fetchCard(id));
for (let attempt = 0; ; attempt++) {
const next = {
...mutate(structuredClone(record.data)),
updatedAt: new Date().toISOString(),
};
try {
// Atomic conditional PUT guarded by ETag
const written = await db.put(`boards/main/cards/${id}`, next, {
ifMatch: record.etag, // Throws ConflictError (412) if another user saved first
});
cards.set(id, { id, data: next, etag: written.etag });
return { ok: true };
} catch (error) {
if (!(error instanceof ConflictError) || attempt >= retries) throw error;
// Race lost: re-fetch winning version and replay the mutation
record = await fetchCard(id);
}
}
}
Explore the full repository on GitHub: github.com/jaydb-cloud/jaydb-kanban-demo.
Architecture Overview
JayDB uses a tiered, decoupled architecture where storage durability is handled by cold object storage, and low latency + concurrency are guaranteed by in-memory ownership rings and QUIC streams.
+-------------------------------------------------------------------------+
| SERVER MODE |
| - fasthttp RESTful HTTP API (GET / PUT / DELETE / LIST) |
| - Memberlist Gossip Discovery (SWIM Protocol) |
| - Lexicographical Partition Ring (Deterministic Owner Node) |
| - Multiplexed QUIC Connection Mesh (Sub-ms Inter-Query Execution) |
+-------------------------------------------------------------------------+
|
v (Internal Core)
+---------------------------------------------------------------------------+
| EMBEDDED MODE |
| (Core Engine Library) |
| |
| +---------------------------------------------------------------------+ |
| | High-Level Go API (Get, Put, Delete, List) | |
| +---------------------------------------------------------------------+ |
| | Key-Level Mutex & Singleflight Cache Manager | |
| | - Flawless Multi-Node Consistency via Owner Node Routing | |
| | - Read Coalescing (1 S3 GET for concurrent readers) | |
| +---------------------------------------------------------------------+ |
| | Pluggable Codec (JSON default, MsgPack, Raw) | |
| +---------------------------------------------------------------------+ |
| | Cold Storage Driver Interface (S3 Driver + FS Driver + Mem Driver) | |
+---------------------------------------------------------------------------+
Core Architectural Components
- Authoritative Key Ownership: Keys are partitioned by path prefix across cluster nodes using a lexicographical ring. Requests for a key always route directly to the single owner node.
- Singleflight Read Coalescing: When 100 concurrent requests hit a cold key, JayDB holds all 100 requests in-flight, executes a single S3
GetObject, and distributes the result to all callers. - Atomic Optimistic Locking (CAS): Updates pass S3
If-Match/If-None-Matchheaders down to the storage layer, ensuring no update is lost even across distributed instances.
JayDB vs Traditional Databases
Why choose JayDB over Postgres, MongoDB, or DynamoDB for modern services and agent applications?
| Capability | Traditional Managed DB (Postgres / Mongo) | DynamoDB / Cloud KV | JayDB (S3-Backed Document DB) |
|---|---|---|---|
| Monthly Base Cost | $15 - $50+/month floor | $0 base + high per-request fees | < $0.32/month on S3 (or $0.00 dev) |
| Infrastructure Ops | Provisioning, scaling, replicas, upgrades | IAM policies, partition keys, WCU/RCU | Zero Ops (100% serverless on S3) |
| Local Dev Setup | Docker, background daemons, migrations | Local emulator container | Zero Dependency (`memory` or `fs` driver) |
| Concurrency Control | Row locks, table locks, connection pools | Conditional expressions | Built-in ETag CAS & Singleflight |
| Data Model | Strict DDL tables / BSON collections | Key-attribute items | Hierarchical Document Paths (`a/b/c`) |
Hierarchical Document Model
JayDB organizes data as a tree of document paths inside isolated namespaces.
A document key is a /-delimited path (e.g. users/101/profile, teams/engineering/projects/jaydb).
- Paths cannot contain leading or trailing slashes (e.g. use users/101, not /users/101/).
- Keys cannot contain consecutive slashes (//) or .. traversals.
- Namespaces partition your data entirely. Two documents with the same key in different namespaces are completely independent.
Compare-and-Swap (CAS)
JayDB uses optimistic concurrency control (OCC) powered by standard HTTP ETag headers. Every document write calculates and returns a new ETag hash.
Guarded Operations
-
Create Only (
If-None-Match: *): The write succeeds only if the key does NOT currently exist. If it exists, returns412 Precondition Failed. -
Conditional Update (
If-Match: "<etag>"): The write succeeds only if the document's current ETag matches what you provide. If another writer updated it first, returns412 Precondition Failed. - Unconditional Write (No headers): Overwrites the key regardless of current version.
curl -X PUT https://acme.jaydb.com/v1/n/app/docs/users/101 \
-H "X-JayDB-API-Key: $JAYDB_KEY" \
-H 'If-Match: "3f9a1c72"' \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "role": "admin"}'
Read-Modify-Write Pattern
To safely mutate documents under concurrent updates without lost writes, use the standard read-modify-write retry loop:
const BASE = 'https://acme.jaydb.com/v1/n/app/docs';
const headers = { 'X-JayDB-API-Key': process.env.JAYDB_KEY };
async function update(key, mutateFn, maxRetries = 5) {
for (let i = 0; i < maxRetries; i++) {
const getRes = await fetch(`${BASE}/${key}`, { headers });
const doc = getRes.ok ? await getRes.json() : {};
const guard = getRes.ok
? { 'If-Match': getRes.headers.get('ETag') }
: { 'If-None-Match': '*' };
const putRes = await fetch(`${BASE}/${key}`, {
method: 'PUT',
headers: { ...headers, ...guard, 'Content-Type': 'application/json' },
body: JSON.stringify(mutateFn(doc)),
});
if (putRes.ok) return putRes.json();
if (putRes.status !== 412) throw new Error(await putRes.text());
}
throw new Error(`Too much contention updating ${key}`);
}
import os, requests
BASE = "https://acme.jaydb.com/v1/n/app/docs"
headers = {"X-JayDB-API-Key": os.environ["JAYDB_KEY"]}
def update(key, mutate_fn, max_retries=5):
for _ in range(max_retries):
r = requests.get(f"{BASE}/{key}", headers=headers)
doc = r.json() if r.status_code == 200 else {}
guard = {"If-Match": r.headers.get("ETag")} if r.status_code == 200 else {"If-None-Match": "*"}
put_r = requests.put(
f"{BASE}/{key}",
headers={**headers, **guard},
json=mutate_fn(doc)
)
if put_r.status_code == 200:
return put_r.json()
if put_r.status_code != 412:
put_r.raise_for_status()
raise RuntimeError(f"High contention on {key}")
// In embedded Go mode, use db.WithExpectedETag or db.CreateOnly
meta, err := database.Put(ctx, "users/101", user, db.WithExpectedETag(readMeta.ETag))
if errors.Is(err, db.ErrPreconditionFailed) {
// Re-read and retry
}
The Kanban Demo App relies on this exact pattern to handle concurrent card movements and collaborative updates conflict-free straight from the browser.
Singleflight Coalescing
In traditional databases and naive S3 integrations, a traffic spike on a single document can result in hundreds of duplicate reads hitting storage.
JayDB incorporates a key-level singleflight coalescing engine. If 1,000 requests for pricing/plans arrive simultaneously while the cache is cold, exactly one S3 GetObject request is dispatched. The other 999 callers await the same in-flight result, eliminating cache stampedes and keeping your S3 bill negligible.
HTTP REST API Reference
The jaydb REST API is lightweight, fast, and completely stateless.
- Base URL:
https://{tenant}.jaydb.com - Prefix:
/v1/n/{namespace}/docs - Authentication: one of the two credentials below on every request
Authentication
The data plane accepts two credentials. Which one you use depends on whether a server of yours is involved at all.
| Header | Identity | Use it for |
|---|---|---|
Authorization: Bearer <jwt> |
The signed-in end user | Frontend-only browser apps. Minted by the tenant's own OIDC issuer. |
X-JayDB-API-Key |
The organization / namespace | Server-side and REST integrations, where the secret stays server-side. |
An API key is scoped to an organization and namespace, not to a single user, and carries no read/write distinction. Anyone who views source gets full read-write over that namespace. Use the bearer path for anything a browser loads.
Sign-in from the browser (OIDC + PKCE)
Every organization gets its own OIDC issuer at https://{tenant}.jaydb.com, publishing standard discovery metadata and a JWKS under that issuer — so tokens are verifiable with any standard OIDC library. Browser clients use Authorization Code + PKCE: no client secret ships to the browser, because the PKCE proof key replaces it.
Register the app first in the console (App Registrations) as a public PKCE client with its client ID, redirect URIs, and allowed origins. Registering the app is what grants its origin cross-origin access to the data plane — there is no operator-managed allowlist to edit. Org admins separately choose which upstream identity providers are offered (Identity Providers): Google, GitHub, Microsoft, any generic OIDC provider, or a custom OAuth2 provider.
For turnkey browser authentication with automated PKCE flow and silent token refresh, use the official Frontend SDK (@jaydb/cloud), or inspect the Kanban Demo App (source code, live demo).
1. Redirect the user to the authorize endpoint
GET https://acme.jaydb.com/oauth/v2/authorize
?response_type=code
&client_id=my-app
&redirect_uri=https://myapp.example/callback
&scope=openid%20profile%20email
&code_challenge=<S256 challenge>
&code_challenge_method=S256
2. Exchange the returned code for a token
POST /oauth/v2/token
Host: acme.jaydb.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=<code from the redirect>
&client_id=my-app
&redirect_uri=https://myapp.example/callback
&code_verifier=<the original verifier>
3. Call the data plane with the token
const res = await fetch(
'https://acme.jaydb.com/v1/n/app/docs/users/101',
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
);
const etag = res.headers.get('ETag'); // exposed cross-origin
const doc = await res.json();
The ETag response header is exposed cross-origin, so browser JavaScript can read it and use it for compare-and-swap. There is no SSE or websocket — clients poll, and because list returns a per-key etag, a poll loop can diff and re-read only what changed.
The endpoint examples below show X-JayDB-API-Key for brevity. Substitute Authorization: Bearer <jwt> unchanged wherever a browser app is the caller.
Read Document
Fetches the JSON document stored at {key}.
| Header | Type | Description |
|---|---|---|
AuthorizationX-JayDB-API-Key |
string | Required — one of the two. Bearer <jwt> for a signed-in browser user, or your secret API key server-side. See Authentication. |
HTTP/1.1 200 OK
ETag: "3f9a1c72"
Content-Type: application/json
{
"name": "Alice",
"role": "admin"
}
Write & CAS Update
Creates or updates the document at {key} with the supplied JSON body.
| Header | Type | Description |
|---|---|---|
Content-Type |
string | Must be application/json. |
If-Match |
string | Optional. ETag from previous read for compare-and-swap update. |
If-None-Match |
string | Optional. Set to * to ensure the document is created only if it does not already exist. |
HTTP/1.1 200 OK
ETag: "8c1e04b5"
Content-Type: application/json
{
"status": "ok",
"key": "users/101",
"etag": "8c1e04b5",
"mod_time": "2026-08-28T01:00:00Z"
}
Delete Document
Removes the document at {key}. Deletes are never billed.
List Keys & Prefix Scan
Lists document metadata matching an optional key path prefix.
| Query Parameter | Type | Description |
|---|---|---|
list |
flag | Required. Flag indicating listing query. |
prefix |
string | Optional. Key prefix filter (e.g. users/). |
limit |
number | Optional. Max items to return (default 100, max 1000). |
cursor |
string | Optional. Opaque pagination token returned in previous response next_cursor. |
{
"items": [
{ "key": "users/101", "etag": "8c1e04b5", "mod_time": "2026-08-28T01:00:00Z", "size": 1204 },
{ "key": "users/102", "etag": "1a77de90", "mod_time": "2026-08-28T01:00:00Z", "size": 980 }
],
"next_cursor": "dXNlcnMvMTAy"
}
Status Codes & Errors
| HTTP Code | Meaning | Action |
|---|---|---|
200 OK |
Operation succeeded | Normal response. |
400 Bad Request |
Invalid path, malformed JSON body, or invalid query parameter | Check payload structure. |
401 Unauthorized |
Missing or invalid X-JayDB-API-Key |
Verify your API key. |
403 Forbidden |
Request did not target a valid tenant subdomain | Ensure using {tenant}.jaydb.com. |
404 Not Found |
Key does not exist | Key is missing or deleted. |
412 Precondition Failed |
ETag mismatch on If-Match or existing key on If-None-Match |
Re-read document and retry CAS update. |
413 Payload Too Large |
Request body exceeded maximum document size limit | Keep documents under 5MB. |
Go Library & Embedded Engine
JayDB can be imported as a pure Go library for direct in-process database execution without any network hops.
go get github.com/avivklas/jaydb
package main
import (
"context"
"fmt"
"log"
"github.com/avivklas/jaydb/pkg/db"
"github.com/avivklas/jaydb/pkg/storage/s3"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
ctx := context.Background()
// 1. Initialize S3 Driver
driver, err := s3.NewDriver(s3.Config{
Bucket: "my-app-documents",
Region: "us-east-1",
})
if err != nil {
log.Fatal(err)
}
// 2. Open Embedded JayDB Instance
database, err := db.Open(db.Options{
Storage: driver,
ShardingDepth: 2, // Key prefix shard depth (e.g. "users/101")
})
if err != nil {
log.Fatal(err)
}
defer database.Close()
// 3. Create Document
user := User{Name: "Alice", Email: "alice@example.com"}
meta, err := database.Put(ctx, "users/101", user, db.CreateOnly())
if err != nil {
log.Fatal(err)
}
fmt.Println("Created user ETag:", meta.ETag)
// 4. Read Document
var fetched User
readMeta, err := database.Get(ctx, "users/101", &fetched)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched user: %+v (ETag: %s)\n", fetched, readMeta.ETag)
}
Storage Drivers
JayDB includes pluggable storage backends implementing the storage.Driver interface:
- S3 Driver (
pkg/storage/s3): Primary cold storage driver. Works with AWS S3, Cloudflare R2, MinIO, and Wasabi. - Filesystem Driver (
pkg/storage/fs): Stores documents on local disk. Ideal for single-node appliances and local testing. - In-Memory Driver (
pkg/storage/memory): Ephemeral in-memory storage for unit tests. Zero external dependencies.
Cache & Sharding Depth
ShardingDepth controls how key paths are hashed into partition rings. For example, with ShardingDepth: 2, a path like orgs/acme/projects/1 is partitioned by the prefix orgs/acme.
Clustering & High Availability
JayDB instances coordinate as a peer-to-peer cluster using SWIM Memberlist Gossip and long-lived multiplexed QUIC streams.
Lexicographical Ring & QUIC Mesh
- Node Discovery: Nodes join via gossip (
JoinAddrs). Node failure detection happens automatically via SWIM protocol. - Deterministic Key Ownership: A lexicographical consistent hash ring routes document requests to the responsible node.
- Sub-Millisecond QUIC Mesh: When a node receives a query for a key owned by another peer, it forwards the query across an established QUIC connection, eliminating TLS handshake overhead.
// Initialize Node 1 (Seed Node)
node1, _ := cluster.NewNode(cluster.NodeConfig{
NodeName: "node-1",
BindAddr: "127.0.0.1",
BindPort: 19001,
QuicPort: 19002,
Ring: ring,
DBHandler: dbInstance1,
})
// Initialize Node 2 (Joins Node 1)
node2, _ := cluster.NewNode(cluster.NodeConfig{
NodeName: "node-2",
BindAddr: "127.0.0.1",
BindPort: 19003,
QuicPort: 19004,
JoinAddrs: []string{"127.0.0.1:19001"},
Ring: ring,
DBHandler: dbInstance2,
})
Observability & Metrics
JayDB exposes native Prometheus metrics out-of-the-box on GET /metrics.
| Metric Name | Type | Description |
|---|---|---|
jaydb_cache_hits_total |
Counter | Total in-memory cache hits. |
jaydb_cache_misses_total |
Counter | Cache misses requiring cold storage read. |
jaydb_singleflight_coalesced_total |
Counter | Concurrent reads coalesced by singleflight engine. |
jaydb_cas_conflicts_total |
Counter | Precondition failed 412 conflicts on CAS updates. |
jaydb_storage_operation_duration_seconds |
Histogram | Latency of cold S3 driver operations. |
jaydb_cluster_nodes |
Gauge | Number of active cluster peers in memberlist. |
Continuous Profiling (Pyroscope)
JayDB Cloud includes continuous CPU, memory allocation, and mutex contention profiling integration with Grafana Pyroscope.
# Access local pprof flamegraphs
./jaydb-cloud server --port 8080
# Profile endpoint: http://localhost:8080/debug/pprof/
S3 Cost Breakdown
How does JayDB run 1,000,000 requests/month for under 32 cents?
| Workload Item | Volume / Month | AWS Standard Rate | Effective Monthly Cost |
|---|---|---|---|
| S3 Document Storage | 2 GB total | $0.023 / GB-month | $0.046 |
| S3 GET Reads | 50,000 cold reads (95% absorbed by cache) | $0.0004 / 1,000 | $0.020 |
| S3 PUT Writes | 50,000 updates | $0.0050 / 1,000 | $0.250 |
| Data In / Out | 100 GB egress | Free tier | $0.000 |
| TOTAL MONTHLY AWS S3 COST | ~$0.316 / month | ||