UNPKG

7.64 kBMarkdownView Raw
1# lowdb [![](http://img.shields.io/npm/dm/lowdb.svg?style=flat)](https://www.npmjs.org/package/lowdb) [![Node.js CI](https://github.com/typicode/lowdb/actions/workflows/node.js.yml/badge.svg)](https://github.com/typicode/lowdb/actions/workflows/node.js.yml)
2
3> Simple to use local JSON database. Use native JavaScript API to query. Written in TypeScript. 🦉
4
5```js
6// Edit db.json content using native JS API
7db.data
8 .posts
9 .push({ id: 1, title: 'lowdb is awesome' })
10
11// Save to file
12db.write()
13```
14
15```js
16// db.json
17{
18 "posts": [
19 { "id": 1, "title": "lowdb is awesome" }
20 ]
21}
22```
23
24If you like lowdb, see also [xv](https://github.com/typicode/xv) (test runner) and [steno](https://github.com/typicode/steno) (fast file writer).
25
26## Sponsors
27
28<br>
29<br>
30
31<p align="center">
32 <a href="https://mockend.com/" target="_blank">
33 <img src="https://jsonplaceholder.typicode.com/mockend.svg" height="70px">
34 </a>
35</p>
36
37<br>
38<br>
39
40[Become a sponsor and have your company logo here](https://github.com/sponsors/typicode).
41
42Please help me build OSS 👉 [GitHub Sponsors](https://github.com/sponsors/typicode)
43
44## Features
45
46- __Lightweight__
47- __Minimalist__
48- __TypeScript__
49- __plain JS__
50- Atomic write
51- Hackable:
52 - Change storage, file format (JSON, YAML, ...) or add encryption via [adapters](#adapters)
53 - Add lodash, ramda, ... for super powers!
54
55## Install
56
57```sh
58npm install lowdb
59```
60
61## Usage
62
63_Lowdb is a pure ESM package. If you're having trouble importing it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)._
64
65```js
66import { join, dirname } from 'node:path'
67import { fileURLToPath } from 'node:url'
68
69// Data will be saved to a local JSON file
70// For browser usage, see examples/ directory
71import { Low } from 'lowdb'
72import { JSONFile } from 'lowdb/node'
73
74const __dirname = dirname(fileURLToPath(import.meta.url));
75
76const file = join(__dirname, 'db.json')
77const adapter = new JSONFile(file)
78const db = new Low(adapter)
79
80// Read data from JSON file, this will set db.data content
81await db.read()
82
83// If db.json doesn't exist, db.data will be null
84// Set default data
85// db.data = db.data || { posts: [] } // Node < v15.x
86db.data ||= { posts: [] } // Node >= 15.x
87
88// Create and query items using native JS API
89db.data.posts.push('hello world')
90const firstPost = db.data.posts[0]
91
92// Alternatively, you can also use this syntax if you prefer
93const { posts } = db.data
94posts.push('hello world')
95
96// Finally write db.data content to file
97await db.write()
98```
99
100```js
101// db.json
102{
103 "posts": [ "hello world" ]
104}
105```
106
107### TypeScript
108
109You can use TypeScript to type check your data.
110
111```ts
112type Data = {
113 words: string[]
114}
115
116const adapter = new JSONFile<Data>('db.json')
117const db = new Low(adapter)
118
119db.data
120 .words
121 .push('foo') // ✅
122
123db.data
124 .words
125 .push(1) // ❌
126```
127
128### Lodash
129
130You can also add lodash or other utility libraries to improve lowdb.
131
132```ts
133import lodash from 'lodash'
134
135type Post = {
136 id: number;
137 title: string;
138}
139
140type Data = {
141 posts: Post[]
142}
143
144// Extend Low class with a new `chain` field
145class LowWithLodash<T> extends Low<T> {
146 chain: lodash.ExpChain<this['data']> = lodash.chain(this).get('data')
147}
148
149const adapter = new JSONFile<Data>('db.json')
150const db = new LowWithLodash(adapter)
151await db.read()
152
153// Instead of db.data use db.chain to access lodash API
154const post = db.chain
155 .get('posts')
156 .find({ id: 1 })
157 .value() // Important: value() must be called to execute chain
158```
159
160### More examples
161
162For CLI, server and browser usage, see [`examples/`](/examples) directory.
163
164## API
165
166### Classes
167
168Lowdb has two classes (for asynchronous and synchronous adapters).
169
170#### `new Low(adapter)`
171
172```js
173import { Low } from 'lowdb'
174import { JSONFile } from 'lowdb/node'
175
176const db = new Low(new JSONFile('file.json'))
177await db.read()
178await db.write()
179```
180
181#### `new LowSync(adapterSync)`
182
183```js
184import { LowSync } from 'lowdb'
185import { JSONFileSync } from 'lowdb/node'
186
187const db = new LowSync(new JSONFileSync('file.json'))
188db.read()
189db.write()
190```
191
192### Methods
193
194#### `db.read()`
195
196Calls `adapter.read()` and sets `db.data`.
197
198**Note:** `JSONFile` and `JSONFileSync` adapters will set `db.data` to `null` if file doesn't exist.
199
200```js
201db.data // === null
202db.read()
203db.data // !== null
204```
205
206#### `db.write()`
207
208Calls `adapter.write(db.data)`.
209
210```js
211db.data = { posts: [] }
212db.write() // file.json will be { posts: [] }
213db.data = {}
214db.write() // file.json will be {}
215```
216
217### Properties
218
219#### `db.data`
220
221Holds your db content. If you're using the adapters coming with lowdb, it can be any type supported by [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
222
223For example:
224
225```js
226db.data = 'string'
227db.data = [1, 2, 3]
228db.data = { key: 'value' }
229```
230
231## Adapters
232
233### Lowdb adapters
234
235#### `JSONFile` `JSONFileSync`
236
237Adapters for reading and writing JSON files.
238
239```js
240new Low(new JSONFile(filename))
241new LowSync(new JSONFileSync(filename))
242```
243
244#### `Memory` `MemorySync`
245
246In-memory adapters. Useful for speeding up unit tests.
247
248```js
249new Low(new Memory())
250new LowSync(new MemorySync())
251```
252
253#### `LocalStorage`
254
255Synchronous adapter for `window.localStorage`.
256
257```js
258new LowSync(new LocalStorage(name))
259```
260
261#### `TextFile` `TextFileSync`
262
263Adapters for reading and writing text. Useful for creating custom adapters.
264
265### Third-party adapters
266
267If you've published an adapter for lowdb, feel free to create a PR to add it here.
268
269### Writing your own adapter
270
271You may want to create an adapter to write `db.data` to YAML, XML, encrypt data, a remote storage, ...
272
273An adapter is a simple class that just needs to expose two methods:
274
275```js
276class AsyncAdapter {
277 read() { /* ... */ } // should return Promise<data>
278 write(data) { /* ... */ } // should return Promise<void>
279}
280
281class SyncAdapter {
282 read() { /* ... */ } // should return data
283 write(data) { /* ... */ } // should return nothing
284}
285```
286
287For example, let's say you have some async storage and want to create an adapter for it:
288
289```js
290import { api } from './AsyncStorage'
291
292class CustomAsyncAdapter {
293 // Optional: your adapter can take arguments
294 constructor(args) {
295 // ...
296 }
297
298 async read() {
299 const data = await api.read()
300 return data
301 }
302
303 async write(data) {
304 await api.write(data)
305 }
306}
307
308const adapter = new CustomAsyncAdapter()
309const db = new Low(adapter)
310```
311
312See [`src/adapters/`](src/adapters) for more examples.
313
314#### Custom serialization
315
316To create an adapter for another format than JSON, you can use `TextFile` or `TextFileSync`.
317
318For example:
319
320```js
321import { Adapter, Low } from 'lowdb'
322import { TextFile } from 'lowdb/node'
323import YAML from 'yaml'
324
325class YAMLFile {
326 constructor(filename) {
327 this.adapter = new TextFile(filename)
328 }
329
330 async read() {
331 const data = await this.adapter.read()
332 if (data === null) {
333 return null
334 } else {
335 return YAML.parse(data)
336 }
337 }
338
339 write(obj) {
340 return this.adapter.write(YAML.stringify(obj))
341 }
342}
343
344const adapter = new YAMLFile('file.yaml')
345const db = new Low(adapter)
346```
347
348## Limits
349
350Lowdb doesn't support Node's cluster module.
351
352If you have large JavaScript objects (`~10-100MB`) you may hit some performance issues. This is because whenever you call `db.write`, the whole `db.data` is serialized using `JSON.stringify` and written to storage.
353
354Depending on your use case, this can be fine or not. It can be mitigated by doing batch operations and calling `db.write` only when you need it.
355
356If you plan to scale, it's highly recommended to use databases like PostgreSQL or MongoDB instead.