{"id":25286799,"url":"https://github.com/jonathanlurie/fstreestore","last_synced_at":"2026-05-05T23:32:23.578Z","repository":{"id":75692865,"uuid":"262595819","full_name":"jonathanlurie/fstreestore","owner":"jonathanlurie","description":"Key-value store on filesystem using a simple tree structure","archived":false,"fork":false,"pushed_at":"2020-05-17T21:27:42.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T16:17:07.107Z","etag":null,"topics":["database","filesystem","key-value","nodejs","nosql","store"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonathanlurie.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-09T15:04:11.000Z","updated_at":"2020-05-17T21:30:42.000Z","dependencies_parsed_at":"2023-06-07T09:35:38.434Z","dependency_job_id":null,"html_url":"https://github.com/jonathanlurie/fstreestore","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jonathanlurie/fstreestore","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanlurie%2Ffstreestore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanlurie%2Ffstreestore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanlurie%2Ffstreestore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanlurie%2Ffstreestore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonathanlurie","download_url":"https://codeload.github.com/jonathanlurie/fstreestore/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanlurie%2Ffstreestore/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32672620,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","filesystem","key-value","nodejs","nosql","store"],"created_at":"2025-02-12T21:51:29.478Z","updated_at":"2026-05-05T23:32:23.561Z","avatar_url":"https://github.com/jonathanlurie.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FSTREESTORE\nFSTREESTORE is a *key-value* store that relies entirely on the filesystem and file/folder tree structure. No server.\n\nHere are some features:\n- Entirely based on the filesystem\n- Five simple operations: `has`, `set`, `get`, `remove`, `list`\n- Fast listing with indexing and self sanitizing\n- No server required\n- A database is just a folder (easy backup, migrate, delete)\n- Need multiple stores? Just instanciate multiple `Store` on different folders\n- No low-level dependencies\n- OK fast\n- Keys can contain any utf-8 characters (emoji, Chinese, etc.) and as long as 36 characters\n- Values can be `null`, *String*, *Number*, *Array*, *Object*, *TypedArray* (including BigInt and Float64) and *Boolean*\n- Numerical values are automatically saved as float or int on 64 bits. Strings are utf-8\n- Serialization file format is efficient, versatile and simple\n\n# Install\n```\nnpm install fstreestore\n```\n\n# Usage\n```js\nconst Store = require('fstreestore')\n\n// A diretory path is expected here. Can be absolute or relative\nlet s = new Store('/somewhere/on/filesystem/myDb')\n\n// All the functions are asynchronous and return promises, so they need to be called\n// with 'await' from an 'async' function (or with '.then() and .catch())\nasync function main() {\n  // Create the provided directory if necessary\n  await s.init()\n  \n  // ** Store a key-value \n\n  // with a string\n  await s.set('a-key', 'a value')\n\n  // with a number (serialized as int64)\n  await s.set('a-key-02', 42)\n\n  // with a number (serialized as float64)\n  await s.set('a-key-03', 42.42)\n\n  // with an Object (serialized as JSON string, utf-8)\n  await s.set('a-key-04', {firstname: 'Johnny', lastname: 'Bravo'})\n\n  // with an (untyped) Array (serialized as JSON string, utf-8)\n  await s.set('a-key-05', [42, 'Johnny Bravo', {foo: 'bar'}])\n  \n  // with a typed array (all flavours are possible)\n  await s.set('a-key-06', new Uin32Array([12, 13, 14]))\n  await s.set('a-key-07', new Float64Array([12.5, 13.3, 14]))\n\n  // with boolean\n  await s.set('a-key-08', true)\n\n  // with null\n  await s.set('a-key-09', null)\n\n\n  // ** Retrieve/get a value, under the type they were saved\n\n  let val02 = await s.get('a-key-02') // 42 --\u003e number\n  let val07 = await s.get('a-key-07') // Float64Array([12.5, 13.3, 14]) --\u003e typed array\n  let val04 = await s.set('a-key-04') // {firstname: 'Johnny', lastname: 'Bravo'} --\u003e object\n\n\n  // ** List all the available keys\n\n  let allKeys = await s.list()\n\n\n  // ** remove data, using the key\n\n  await s.remove('a-key-02') \n}\n\nmain()\n```\n\n# Key format\nThe only constraint for the keys is that they are at least 1 character long and at most 36. Apart from that, all the utf-8 charaters are possible, including emojis, accentuated, Chinese, etc.\n\nExample:\n```js\nawait s.set('drum 🥁', new Float32Array([12, 34.34, Math.PI]))\n```\n\n# A word on Errors\nFSTREESTORE will throw errors if the provided key does not respect (empty string or longer than 36 characters).\n\nIn addition, the `.get()` will throw an error if the key is not existing. To prevent `get` from thowing, it must be used as follow `.get('some key', {throw: false})`, then a `null` value will be returned if `'some key'` does not exist.\n\n# Listing and precautions\nSince FSTREESTORE's database are entirely based on the filesystem, it makes all the data easily accessible, but the files and folder in there are to be accessed only by FSTREESTORE and should not be modified manually, otherwise the whole DB might get corrupted.\n\nThis is particularly true for the `list` file, that makes the listing possible in a reasonable amount of time. This file keeps an index of what is added and removed. Every time `.list()` is called, the list file gets sanitized under the hood, removing duplicates and deleted keys to keep only the remaining keys. The list is automatically sanitized every 5000 set/remove operations.\n\n# Compatibility\nFSTREESTORE was developed and tested on MacOS and probably works on Linux. It was not tested on Windows and I am pretty sure it would not work due to the Windows filesystem being very different from Unix-like fs.\n\n# Why?\nThe idea first came when I started to look for a *key-value* store that I could run close to a Nodejs app, that did not require a server and was fast and versatile enough. I stumbled upon the excellent **LMDB** (and its [Node wrapper](https://www.npmjs.com/package/node-lmdb)) and started playing with it. Then I wondered how it was working under the hood and looked up B+ trees and stuff like that, and even though **FSTREESTORE** does not use a B+ tree, it's still loosely inspired by this concept. Also, not relying on low level dependencies can prevent having some plateform issues.  \nFinally, the main reason is that it was fun to to and I was curious about the performance of such a naive store implementation.\n\n# Performance\nIn the first part, performances were said to be \"OK fast\", this is obviously relative to one's habit and expectation (as well as one's configuration). In other word, let's just say it's a hobby store that is tailords for hobby projects, and it costs zero in DB server money.\n```\nCREATE time (ms): 822.414488017559   iterations: 1000  ops: 1215\nREAD time (ms): 372.39405900239944   iterations: 1000  ops: 2685\nDELETE time (ms): 651.8716329932213   iterations: 1000  ops: 1534\n```\n\nObviously, these are nowhere near the ~50000 operations per seconds (ops) I get with `LMDB` in the same conditions, but I knew since the very begining that I would never be even close with such a naive approach that relies entirely on creating folders and files on the filesystem!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanlurie%2Ffstreestore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathanlurie%2Ffstreestore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanlurie%2Ffstreestore/lists"}