0
# Storage Backends
1
2
OrbitDB provides a flexible storage system with multiple backend implementations for different use cases. Storage backends handle persistence of database entries, heads, and indices.
3
4
## Capabilities
5
6
### Storage Interface
7
8
All storage backends implement a common interface for consistency.
9
10
```javascript { .api }
11
interface Storage {
12
/** Stores data at the given key */
13
put(key: string, value: any): Promise<void>;
14
/** Retrieves data by key */
15
get(key: string): Promise<any>;
16
/** Deletes data at the given key */
17
del(key: string): Promise<void>;
18
/** Lists all keys (optional) */
19
keys?(): Promise<string[]>;
20
/** Clears all data (optional) */
21
clear?(): Promise<void>;
22
/** Closes the storage backend (optional) */
23
close?(): Promise<void>;
24
}
25
```
26
27
### IPFS Block Storage
28
29
Stores data as IPFS blocks, leveraging IPFS's content addressing and distributed storage.
30
31
```javascript { .api }
32
/**
33
* Creates an IPFS block storage instance
34
* @param params Configuration parameters
35
* @param params.ipfs IPFS instance to use
36
* @param params.pin Whether to pin blocks (default: false)
37
* @returns Promise resolving to IPFSBlockStorage instance
38
*/
39
function IPFSBlockStorage(params: {
40
ipfs: IPFS;
41
pin?: boolean;
42
}): Promise<IPFSBlockStorage>;
43
44
interface IPFSBlockStorage extends Storage {
45
/** Stores data as IPFS block */
46
put(hash: string, data: Uint8Array): Promise<void>;
47
/** Retrieves IPFS block data */
48
get(hash: string): Promise<Uint8Array>;
49
/** Unpins and removes IPFS block */
50
del(hash: string): Promise<void>;
51
}
52
```
53
54
**Usage Examples:**
55
56
```javascript
57
import { createHelia } from 'helia';
58
import { createOrbitDB, IPFSBlockStorage } from '@orbitdb/core';
59
60
const ipfs = await createHelia();
61
const orbitdb = await createOrbitDB({ ipfs });
62
63
// Create database with IPFS block storage
64
const db = await orbitdb.open('ipfs-stored-db', {
65
entryStorage: await IPFSBlockStorage({ ipfs, pin: true }),
66
headsStorage: await IPFSBlockStorage({ ipfs, pin: true })
67
});
68
69
// Data is stored as IPFS blocks
70
await db.add('This data is stored as IPFS blocks');
71
72
// Blocks are content-addressed and can be retrieved from any IPFS node
73
const entries = db.log.entries;
74
console.log('Entry stored at IPFS hash:', entries[0].hash);
75
```
76
77
### Level Storage
78
79
LevelDB-based storage for high-performance local persistence.
80
81
```javascript { .api }
82
/**
83
* Creates a Level storage instance
84
* @param params Configuration parameters
85
* @param params.path Directory path for LevelDB
86
* @param params.options LevelDB options
87
* @returns Promise resolving to LevelStorage instance
88
*/
89
function LevelStorage(params: {
90
path: string;
91
options?: any;
92
}): Promise<LevelStorage>;
93
94
interface LevelStorage extends Storage {
95
/** Stores key-value pair in LevelDB */
96
put(key: string, value: any): Promise<void>;
97
/** Retrieves value by key from LevelDB */
98
get(key: string): Promise<any>;
99
/** Deletes key from LevelDB */
100
del(key: string): Promise<void>;
101
/** Lists all keys in LevelDB */
102
keys(): Promise<string[]>;
103
/** Clears all data from LevelDB */
104
clear(): Promise<void>;
105
/** Closes LevelDB connection */
106
close(): Promise<void>;
107
}
108
```
109
110
**Usage Examples:**
111
112
```javascript
113
import { createOrbitDB, LevelStorage } from '@orbitdb/core';
114
115
const ipfs = await createHelia();
116
const orbitdb = await createOrbitDB({ ipfs });
117
118
// Create Level storage instances
119
const headsStorage = await LevelStorage({ path: './db-heads' });
120
const entryStorage = await LevelStorage({ path: './db-entries' });
121
const indexStorage = await LevelStorage({ path: './db-index' });
122
123
// Create database with Level storage
124
const db = await orbitdb.open('level-db', {
125
headsStorage,
126
entryStorage,
127
indexStorage
128
});
129
130
// Data persists to local LevelDB files
131
await db.add('Persistent data');
132
await db.close();
133
134
// Clean up storage
135
await headsStorage.close();
136
await entryStorage.close();
137
await indexStorage.close();
138
```
139
140
### LRU Storage
141
142
LRU (Least Recently Used) cache storage for memory-efficient operations with automatic eviction.
143
144
```javascript { .api }
145
/**
146
* Creates an LRU storage instance
147
* @param params Configuration parameters
148
* @param params.size Maximum number of items to cache (default: 1000)
149
* @returns Promise resolving to LRUStorage instance
150
*/
151
function LRUStorage(params?: {
152
size?: number;
153
}): Promise<LRUStorage>;
154
155
interface LRUStorage extends Storage {
156
/** Stores item in LRU cache */
157
put(key: string, value: any): Promise<void>;
158
/** Retrieves item from LRU cache */
159
get(key: string): Promise<any>;
160
/** Removes item from LRU cache */
161
del(key: string): Promise<void>;
162
/** Gets current cache size */
163
size(): number;
164
/** Clears the cache */
165
clear(): Promise<void>;
166
}
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
import { createOrbitDB, LRUStorage } from '@orbitdb/core';
173
174
const ipfs = await createHelia();
175
const orbitdb = await createOrbitDB({ ipfs });
176
177
// Create LRU storage with custom size
178
const lruStorage = await LRUStorage({ size: 500 });
179
180
// Use as entry cache for frequently accessed data
181
const db = await orbitdb.open('cached-db', {
182
entryStorage: lruStorage
183
});
184
185
// Frequently accessed entries stay in memory
186
await db.add('Cached entry 1');
187
await db.add('Cached entry 2');
188
189
console.log('Cache size:', lruStorage.size());
190
191
// Older entries are evicted when cache is full
192
for (let i = 0; i < 600; i++) {
193
await db.add(`Entry ${i}`);
194
}
195
196
console.log('Cache size after overflow:', lruStorage.size()); // Still 500
197
```
198
199
### Memory Storage
200
201
In-memory storage for temporary data and testing scenarios.
202
203
```javascript { .api }
204
/**
205
* Creates a memory storage instance
206
* @returns Promise resolving to MemoryStorage instance
207
*/
208
function MemoryStorage(): Promise<MemoryStorage>;
209
210
interface MemoryStorage extends Storage {
211
/** Stores item in memory */
212
put(key: string, value: any): Promise<void>;
213
/** Retrieves item from memory */
214
get(key: string): Promise<any>;
215
/** Removes item from memory */
216
del(key: string): Promise<void>;
217
/** Lists all keys in memory */
218
keys(): Promise<string[]>;
219
/** Clears all data from memory */
220
clear(): Promise<void>;
221
}
222
```
223
224
**Usage Examples:**
225
226
```javascript
227
import { createOrbitDB, MemoryStorage } from '@orbitdb/core';
228
229
const ipfs = await createHelia();
230
const orbitdb = await createOrbitDB({ ipfs });
231
232
// Create in-memory database (no persistence)
233
const memoryStorage = await MemoryStorage();
234
const db = await orbitdb.open('temp-db', {
235
entryStorage: memoryStorage,
236
headsStorage: memoryStorage,
237
indexStorage: memoryStorage
238
});
239
240
// Data exists only in memory
241
await db.add('Temporary data');
242
await db.add('Will be lost on restart');
243
244
// Check memory contents
245
const keys = await memoryStorage.keys();
246
console.log('Stored keys:', keys);
247
248
// Clear all data
249
await memoryStorage.clear();
250
```
251
252
### Composed Storage
253
254
Combines multiple storage backends into a hierarchical storage system.
255
256
```javascript { .api }
257
/**
258
* Creates a composed storage instance
259
* @param storages Array of storage backends in order of preference
260
* @returns Promise resolving to ComposedStorage instance
261
*/
262
function ComposedStorage(storages: Storage[]): Promise<ComposedStorage>;
263
264
interface ComposedStorage extends Storage {
265
/** Stores item in all storage backends */
266
put(key: string, value: any): Promise<void>;
267
/** Retrieves item from first available storage backend */
268
get(key: string): Promise<any>;
269
/** Removes item from all storage backends */
270
del(key: string): Promise<void>;
271
/** Closes all storage backends */
272
close(): Promise<void>;
273
}
274
```
275
276
**Usage Examples:**
277
278
```javascript
279
import {
280
createOrbitDB,
281
ComposedStorage,
282
MemoryStorage,
283
LevelStorage,
284
IPFSBlockStorage
285
} from '@orbitdb/core';
286
287
const ipfs = await createHelia();
288
const orbitdb = await createOrbitDB({ ipfs });
289
290
// Create hierarchical storage: Memory -> Level -> IPFS
291
const composedStorage = await ComposedStorage([
292
await MemoryStorage(), // Fast L1 cache
293
await LevelStorage({ path: './cache' }), // L2 persistent cache
294
await IPFSBlockStorage({ ipfs }) // L3 distributed storage
295
]);
296
297
// Create database with composed storage
298
const db = await orbitdb.open('composed-db', {
299
entryStorage: composedStorage
300
});
301
302
// Data is stored in all layers but retrieved from fastest available
303
await db.add('Multi-layer stored data');
304
305
// Reads are served from memory when available
306
const allData = await db.all(); // Fast memory read
307
console.log('Data retrieved:', allData);
308
```
309
310
### Custom Storage Backends
311
312
Create custom storage backends for specific requirements.
313
314
```javascript { .api }
315
/**
316
* Template for custom storage implementation
317
*/
318
interface CustomStorage extends Storage {
319
put(key: string, value: any): Promise<void>;
320
get(key: string): Promise<any>;
321
del(key: string): Promise<void>;
322
keys?(): Promise<string[]>;
323
clear?(): Promise<void>;
324
close?(): Promise<void>;
325
}
326
```
327
328
**Usage Examples:**
329
330
```javascript
331
// Example: Redis-based storage backend
332
class RedisStorage {
333
constructor(redisClient) {
334
this.redis = redisClient;
335
}
336
337
async put(key, value) {
338
await this.redis.set(key, JSON.stringify(value));
339
}
340
341
async get(key) {
342
const value = await this.redis.get(key);
343
return value ? JSON.parse(value) : null;
344
}
345
346
async del(key) {
347
await this.redis.del(key);
348
}
349
350
async keys() {
351
return this.redis.keys('*');
352
}
353
354
async clear() {
355
const keys = await this.keys();
356
if (keys.length > 0) {
357
await this.redis.del(...keys);
358
}
359
}
360
361
async close() {
362
await this.redis.quit();
363
}
364
}
365
366
// Usage with OrbitDB
367
const redis = new Redis(); // Redis client
368
const redisStorage = new RedisStorage(redis);
369
370
const db = await orbitdb.open('redis-db', {
371
entryStorage: redisStorage
372
});
373
```
374
375
### S3-Compatible Storage Example
376
377
```javascript
378
// Example: S3-compatible storage backend
379
class S3Storage {
380
constructor(s3Client, bucketName) {
381
this.s3 = s3Client;
382
this.bucket = bucketName;
383
}
384
385
async put(key, value) {
386
await this.s3.putObject({
387
Bucket: this.bucket,
388
Key: key,
389
Body: JSON.stringify(value),
390
ContentType: 'application/json'
391
}).promise();
392
}
393
394
async get(key) {
395
try {
396
const result = await this.s3.getObject({
397
Bucket: this.bucket,
398
Key: key
399
}).promise();
400
return JSON.parse(result.Body.toString());
401
} catch (error) {
402
if (error.code === 'NoSuchKey') {
403
return null;
404
}
405
throw error;
406
}
407
}
408
409
async del(key) {
410
await this.s3.deleteObject({
411
Bucket: this.bucket,
412
Key: key
413
}).promise();
414
}
415
416
async keys() {
417
const result = await this.s3.listObjectsV2({
418
Bucket: this.bucket
419
}).promise();
420
return result.Contents.map(obj => obj.Key);
421
}
422
423
async clear() {
424
const keys = await this.keys();
425
if (keys.length > 0) {
426
await this.s3.deleteObjects({
427
Bucket: this.bucket,
428
Delete: {
429
Objects: keys.map(Key => ({ Key }))
430
}
431
}).promise();
432
}
433
}
434
}
435
436
// Usage
437
const s3Storage = new S3Storage(s3Client, 'my-orbitdb-bucket');
438
const db = await orbitdb.open('s3-db', {
439
entryStorage: s3Storage
440
});
441
```
442
443
### Storage Configuration Strategies
444
445
Different strategies for configuring storage backends based on use cases.
446
447
```javascript
448
import {
449
createOrbitDB,
450
MemoryStorage,
451
LevelStorage,
452
IPFSBlockStorage,
453
ComposedStorage
454
} from '@orbitdb/core';
455
456
const ipfs = await createHelia();
457
const orbitdb = await createOrbitDB({ ipfs });
458
459
// Strategy 1: All in memory (development/testing)
460
const devDb = await orbitdb.open('dev-db', {
461
headsStorage: await MemoryStorage(),
462
entryStorage: await MemoryStorage(),
463
indexStorage: await MemoryStorage()
464
});
465
466
// Strategy 2: Persistent local storage (production)
467
const prodDb = await orbitdb.open('prod-db', {
468
headsStorage: await LevelStorage({ path: './prod/heads' }),
469
entryStorage: await LevelStorage({ path: './prod/entries' }),
470
indexStorage: await LevelStorage({ path: './prod/index' })
471
});
472
473
// Strategy 3: Hybrid storage (performance + persistence)
474
const hybridDb = await orbitdb.open('hybrid-db', {
475
headsStorage: await ComposedStorage([
476
await MemoryStorage(),
477
await LevelStorage({ path: './heads' })
478
]),
479
entryStorage: await ComposedStorage([
480
await LRUStorage({ size: 1000 }),
481
await LevelStorage({ path: './entries' }),
482
await IPFSBlockStorage({ ipfs })
483
]),
484
indexStorage: await LevelStorage({ path: './index' })
485
});
486
487
// Strategy 4: Distributed storage (IPFS-first)
488
const distributedDb = await orbitdb.open('distributed-db', {
489
entryStorage: await IPFSBlockStorage({ ipfs, pin: true }),
490
headsStorage: await ComposedStorage([
491
await MemoryStorage(),
492
await IPFSBlockStorage({ ipfs, pin: true })
493
]),
494
indexStorage: await LevelStorage({ path: './index' })
495
});
496
```
497
498
### Storage Monitoring and Metrics
499
500
Monitor storage performance and usage.
501
502
```javascript
503
// Wrapper for storage monitoring
504
class MonitoredStorage {
505
constructor(storage, name) {
506
this.storage = storage;
507
this.name = name;
508
this.metrics = {
509
puts: 0,
510
gets: 0,
511
dels: 0,
512
errors: 0
513
};
514
}
515
516
async put(key, value) {
517
try {
518
const start = Date.now();
519
await this.storage.put(key, value);
520
this.metrics.puts++;
521
console.log(`${this.name} PUT ${key} took ${Date.now() - start}ms`);
522
} catch (error) {
523
this.metrics.errors++;
524
throw error;
525
}
526
}
527
528
async get(key) {
529
try {
530
const start = Date.now();
531
const result = await this.storage.get(key);
532
this.metrics.gets++;
533
console.log(`${this.name} GET ${key} took ${Date.now() - start}ms`);
534
return result;
535
} catch (error) {
536
this.metrics.errors++;
537
throw error;
538
}
539
}
540
541
async del(key) {
542
try {
543
const start = Date.now();
544
await this.storage.del(key);
545
this.metrics.dels++;
546
console.log(`${this.name} DEL ${key} took ${Date.now() - start}ms`);
547
} catch (error) {
548
this.metrics.errors++;
549
throw error;
550
}
551
}
552
553
getMetrics() {
554
return { ...this.metrics };
555
}
556
}
557
558
// Usage
559
const levelStorage = await LevelStorage({ path: './monitored' });
560
const monitoredStorage = new MonitoredStorage(levelStorage, 'Level');
561
562
const db = await orbitdb.open('monitored-db', {
563
entryStorage: monitoredStorage
564
});
565
566
// Operations are automatically monitored
567
await db.add('Monitored operation');
568
console.log('Storage metrics:', monitoredStorage.getMetrics());
569
```
570
571
### Error Handling
572
573
Handle storage-related errors appropriately.
574
575
```javascript
576
import { LevelStorage, MemoryStorage } from '@orbitdb/core';
577
578
// Graceful fallback to memory storage
579
async function createResilientStorage(path) {
580
try {
581
return await LevelStorage({ path });
582
} catch (error) {
583
console.warn(`Failed to create Level storage at ${path}:`, error.message);
584
console.log('Falling back to memory storage');
585
return await MemoryStorage();
586
}
587
}
588
589
// Usage with error handling
590
try {
591
const storage = await createResilientStorage('./database');
592
const db = await orbitdb.open('resilient-db', {
593
entryStorage: storage
594
});
595
596
await db.add('Data with resilient storage');
597
} catch (error) {
598
console.error('Storage operation failed:', error.message);
599
}
600
601
// Storage cleanup on shutdown
602
process.on('SIGINT', async () => {
603
try {
604
await storage.close();
605
console.log('Storage closed cleanly');
606
} catch (error) {
607
console.error('Error closing storage:', error.message);
608
}
609
process.exit(0);
610
});
611
```
612
613
Storage backends provide the foundation for OrbitDB's data persistence, enabling everything from ephemeral in-memory databases to highly distributed IPFS-backed storage systems.