GUN is decentralized by default, meaning there’s no single master server or central authority controlling the data. Instead, every peer (browser, server, mobile app) can read, write, and sync data directly with other peers in a mesh network.
Traditional databases use a master-slave architecture where all data flows through a central server. GUN eliminates this bottleneck entirely.
var hear = mesh.hear = function(raw, peer){ if(!raw){ return } if(opt.max <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) } // Parse and process message // Then route to other peers}
Messages are routed using the DAM (Data At Mesh) protocol.
{ '#': 'message_id', // Unique message ID '##': 'hash', // Content hash for deduplication '@': 'ack_to_message', // Acknowledgment of another message '><': 'peer1,peer2', // Peers that already received this 'put': { /* data */ }, // Data being written 'get': { /* query */ } // Data being requested}
// Write data on peer Agun.get('user').put({name: 'Alice'});// Internally, GUN creates a message:{ '#': 'abc123', 'put': { '#': 'user', '.': 'name', ':': 'Alice', '>': 1234567890 }}// This message flows through the mesh to all connected peers
From src/mesh.js:127-147, the say function handles broadcasting:
var say = mesh.say = function(msg, peer){ if(!msg){ return false } var id, hash, raw, ack = msg['@']; var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = String.random(9) } !loop && dup_track(id); // Track message // Broadcast to peer(s) if(!peer && mesh.way){ return mesh.way(msg) } // ... routing logic}
// Request data on peer Bgun.get('user').get('name').once(name => { console.log(name); // 'Alice'});// GUN sends a GET message through mesh{ '#': 'def456', 'get': { '#': 'user', '.': 'name' }}// Any peer with the data responds with a PUT
GUN uses eventual consistency - all peers will eventually have the same data:
// Peer A writesgun.get('counter').put({value: 1});// Peer B writes (at the same time)gun.get('counter').put({value: 2});// GUN uses state (timestamps) to resolve conflicts// The write with the higher timestamp wins
GUN uses CRDTs (Conflict-free Replicated Data Types) to automatically resolve conflicts. Learn more in CRDT Concepts.
// Two GUN instances in same process share meshvar gun1 = Gun();var gun2 = Gun();// They automatically syncgun1.get('test').put({msg: 'hello'});gun2.get('test').on(data => console.log(data)); // {msg: 'hello'}
// Network splits into two partitions[Peer A, Peer B] ↮ [Peer C, Peer D]// Each partition continues working independentlyPeer A writes: {value: 'x'}Peer C writes: {value: 'y'}// When network heals[Peer A, Peer B] ←→ [Peer C, Peer D]// GUN's CRDT resolution handles conflicts automatically// The write with higher timestamp wins
GUN is partition tolerant (the ‘P’ in CAP theorem). It continues working even when the network splits.
// Each user runs this codevar gun = Gun(['https://relay.chat.app/gun']);var chat = gun.get('chatroom');// Send message (writes to local peer + broadcasts)chat.get('messages').set({ from: 'alice', text: 'Hello world!', time: Date.now()});// Receive messages (from any peer in mesh)chat.get('messages').map().on(msg => { console.log(`${msg.from}: ${msg.text}`);});// Works even if relay goes down!// If offline, queues messages and syncs when back online