0
# Node.js File Storage
1
2
File-based storage adapters and convenience presets for Node.js environments. These adapters support JSON files, plain text files, and custom data formats with atomic write operations for data safety.
3
4
## Capabilities
5
6
### JSON File Presets
7
8
Pre-configured database instances with JSON file adapters for immediate use.
9
10
```typescript { .api }
11
/**
12
* Create a Low instance with JSONFile adapter, automatically switches to Memory adapter during tests
13
* @param filename - Path to the JSON file
14
* @param defaultData - Default data structure
15
* @returns Promise resolving to configured Low instance with data pre-loaded
16
*/
17
function JSONFilePreset<Data>(filename: PathLike, defaultData: Data): Promise<Low<Data>>;
18
19
/**
20
* Create a LowSync instance with JSONFileSync adapter, automatically switches to MemorySync adapter during tests
21
* @param filename - Path to the JSON file
22
* @param defaultData - Default data structure
23
* @returns Configured LowSync instance with data pre-loaded
24
*/
25
function JSONFileSyncPreset<Data>(filename: PathLike, defaultData: Data): LowSync<Data>;
26
```
27
28
**Usage Examples:**
29
30
```typescript
31
import { JSONFilePreset, JSONFileSyncPreset } from "lowdb/node";
32
33
// Async preset
34
type Data = { posts: Array<{ id: number; title: string }> };
35
const defaultData: Data = { posts: [] };
36
37
const db = await JSONFilePreset("db.json", defaultData);
38
await db.update(({ posts }) => posts.push({ id: 1, title: "Hello World" }));
39
40
// Sync preset
41
const syncDb = JSONFileSyncPreset("sync-db.json", { settings: {} });
42
syncDb.update((data) => {
43
data.settings.theme = "dark";
44
});
45
```
46
47
### JSON File Adapters
48
49
Direct JSON file adapters with automatic parsing and formatting.
50
51
```typescript { .api }
52
/**
53
* Async JSON file adapter with automatic JSON parsing/stringifying
54
* @template T - The type of data stored in the JSON file
55
*/
56
class JSONFile<T> implements Adapter<T> {
57
constructor(filename: PathLike);
58
59
/** Read and parse JSON file content, returns null if file doesn't exist */
60
read(): Promise<T | null>;
61
62
/** Stringify and write data to JSON file with atomic write operation */
63
write(obj: T): Promise<void>;
64
}
65
66
/**
67
* Sync JSON file adapter with automatic JSON parsing/stringifying
68
* @template T - The type of data stored in the JSON file
69
*/
70
class JSONFileSync<T> implements SyncAdapter<T> {
71
constructor(filename: PathLike);
72
73
/** Read and parse JSON file content synchronously, returns null if file doesn't exist */
74
read(): T | null;
75
76
/** Stringify and write data to JSON file synchronously with atomic write operation */
77
write(obj: T): void;
78
}
79
```
80
81
**Usage Examples:**
82
83
```typescript
84
import { Low, LowSync } from "lowdb";
85
import { JSONFile, JSONFileSync } from "lowdb/node";
86
87
// Async JSON file adapter
88
const adapter = new JSONFile("data.json");
89
const db = new Low(adapter, { users: [] });
90
await db.read();
91
db.data.users.push({ id: 1, name: "Alice" });
92
await db.write();
93
94
// Sync JSON file adapter
95
const syncAdapter = new JSONFileSync("config.json");
96
const syncDb = new LowSync(syncAdapter, { theme: "light" });
97
syncDb.read();
98
syncDb.data.theme = "dark";
99
syncDb.write();
100
```
101
102
### Text File Adapters
103
104
Raw text file adapters for custom data formats and plain text storage.
105
106
```typescript { .api }
107
/**
108
* Async text file adapter using steno for atomic writes
109
*/
110
class TextFile implements Adapter<string> {
111
constructor(filename: PathLike);
112
113
/** Read text file content, returns null if file doesn't exist */
114
read(): Promise<string | null>;
115
116
/** Write text to file with atomic write operation using steno */
117
write(str: string): Promise<void>;
118
}
119
120
/**
121
* Sync text file adapter with atomic writes using temporary files
122
*/
123
class TextFileSync implements SyncAdapter<string> {
124
constructor(filename: PathLike);
125
126
/** Read text file content synchronously, returns null if file doesn't exist */
127
read(): string | null;
128
129
/** Write text to file synchronously with atomic write using temporary file */
130
write(str: string): void;
131
}
132
```
133
134
**Usage Examples:**
135
136
```typescript
137
import { Low, LowSync } from "lowdb";
138
import { TextFile, TextFileSync } from "lowdb/node";
139
140
// Async text file adapter
141
const textAdapter = new TextFile("log.txt");
142
const logDb = new Low(textAdapter, "");
143
await logDb.read();
144
await logDb.update((data) => data + "New log entry\n");
145
146
// Sync text file adapter
147
const syncTextAdapter = new TextFileSync("notes.txt");
148
const notesDb = new LowSync(syncTextAdapter, "");
149
notesDb.read();
150
notesDb.data += "Important note\n";
151
notesDb.write();
152
```
153
154
### Data File Adapters
155
156
Flexible adapters for custom data formats with configurable parse and stringify functions.
157
158
```typescript { .api }
159
/**
160
* Async data file adapter with custom parse/stringify functions
161
* @template T - The type of data stored
162
*/
163
class DataFile<T> implements Adapter<T> {
164
constructor(
165
filename: PathLike,
166
options: {
167
parse: (str: string) => T;
168
stringify: (data: T) => string;
169
}
170
);
171
172
/** Read file content and parse using custom parse function */
173
read(): Promise<T | null>;
174
175
/** Stringify data using custom stringify function and write to file */
176
write(obj: T): Promise<void>;
177
}
178
179
/**
180
* Sync data file adapter with custom parse/stringify functions
181
* @template T - The type of data stored
182
*/
183
class DataFileSync<T> implements SyncAdapter<T> {
184
constructor(
185
filename: PathLike,
186
options: {
187
parse: (str: string) => T;
188
stringify: (data: T) => string;
189
}
190
);
191
192
/** Read file content and parse using custom parse function synchronously */
193
read(): T | null;
194
195
/** Stringify data using custom stringify function and write to file synchronously */
196
write(obj: T): void;
197
}
198
```
199
200
**Usage Examples:**
201
202
```typescript
203
import { Low } from "lowdb";
204
import { DataFile } from "lowdb/node";
205
import YAML from "yaml";
206
207
// YAML file adapter
208
const yamlAdapter = new DataFile("config.yaml", {
209
parse: YAML.parse,
210
stringify: YAML.stringify
211
});
212
213
const yamlDb = new Low(yamlAdapter, { servers: [] });
214
await yamlDb.read();
215
216
// CSV file adapter with custom parsing
217
const csvAdapter = new DataFile("data.csv", {
218
parse: (str) => str.split('\n').map(line => line.split(',')),
219
stringify: (data) => data.map(row => row.join(',')).join('\n')
220
});
221
222
// Encrypted JSON adapter
223
const encryptedAdapter = new DataFile("secret.json", {
224
parse: (str) => JSON.parse(decrypt(str)),
225
stringify: (data) => encrypt(JSON.stringify(data))
226
});
227
```
228
229
## File System Behavior
230
231
### Atomic Writes
232
233
All file adapters use atomic write operations to prevent data corruption:
234
235
- **TextFile**: Uses the `steno` library for atomic writes with temporary files
236
- **TextFileSync**: Creates temporary files and uses `fs.renameSync` for atomic operations
237
- **JSONFile/JSONFileSync**: Inherit atomic behavior from TextFile adapters
238
- **DataFile/DataFileSync**: Inherit atomic behavior from TextFile adapters
239
240
### File Not Found Handling
241
242
When a file doesn't exist:
243
244
```typescript
245
const db = await JSONFilePreset("nonexistent.json", { count: 0 });
246
// db.data will be { count: 0 } (default data)
247
248
await db.read(); // No error thrown, uses default data
249
// db.data remains { count: 0 }
250
251
await db.write(); // Creates the file with current data
252
```
253
254
### Directory Creation
255
256
File adapters do not automatically create parent directories. Ensure directories exist:
257
258
```typescript
259
import { mkdir } from "fs/promises";
260
import { JSONFilePreset } from "lowdb/node";
261
262
// Create directory if needed
263
await mkdir("data", { recursive: true });
264
const db = await JSONFilePreset("data/app.json", {});
265
```
266
267
## Test Environment Behavior
268
269
Presets automatically switch to memory adapters when `NODE_ENV=test`:
270
271
```typescript
272
// In test environment (NODE_ENV=test)
273
const db = await JSONFilePreset("db.json", { posts: [] });
274
// Uses Memory adapter instead of JSONFile
275
// No actual file I/O occurs during testing
276
277
// In production environment
278
const db = await JSONFilePreset("db.json", { posts: [] });
279
// Uses JSONFile adapter for actual file persistence
280
```
281
282
## Error Handling
283
284
File adapters may throw various Node.js file system errors:
285
286
```typescript
287
import { JSONFilePreset } from "lowdb/node";
288
289
try {
290
const db = await JSONFilePreset("/readonly/db.json", {});
291
await db.write();
292
} catch (error) {
293
if (error.code === "EACCES") {
294
console.error("Permission denied");
295
} else if (error.code === "ENOENT") {
296
console.error("Directory doesn't exist");
297
} else if (error.code === "ENOSPC") {
298
console.error("No space left on device");
299
}
300
}
301
302
// Handle JSON parsing errors
303
try {
304
const db = await JSONFilePreset("malformed.json", {});
305
await db.read();
306
} catch (error) {
307
if (error instanceof SyntaxError) {
308
console.error("Invalid JSON format");
309
}
310
}
311
```
312
313
## Performance Considerations
314
315
### Sync vs Async
316
317
- **Async adapters**: Non-blocking I/O, suitable for servers and applications with concurrent operations
318
- **Sync adapters**: Blocking I/O, suitable for CLI tools and simple scripts
319
320
### File Size
321
322
lowdb loads the entire file into memory. For large datasets (>100MB), consider:
323
324
- Splitting data across multiple files
325
- Using streaming database solutions
326
- Implementing custom adapters with partial loading
327
328
### Write Frequency
329
330
Atomic writes create temporary files. For high-frequency writes:
331
332
- Batch updates using the `update()` method
333
- Consider using Memory adapters with periodic persistence
334
- Implement custom adapters with write buffering
335
336
## Types
337
338
```typescript { .api }
339
/** Node.js path-like type (string, Buffer, or URL) */
340
type PathLike = string | Buffer | URL;
341
```