npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

octavedb

v1.0.0

Published

A simple, TypeScript-first JSON file database for local development and prototyping

Readme

OctaveDB

A simple, TypeScript-first JSON file database for local development and prototyping.

⚠️ Important: When to use this

✅ Good for:

  • Local development and prototyping
  • CLI tools and desktop apps
  • Demo projects and tutorials
  • Single-user applications
  • Projects where simplicity > scalability

❌ Not for:

  • Production web applications
  • Multi-user environments
  • Applications requiring ACID compliance
  • Sensitive data (no encryption)
  • High-concurrency scenarios

If you need a production database, use PostgreSQL, MySQL, SQLite, etc.

Why OctaveDB?

  • 🎯 Zero configuration - no database server to install
  • 🔒 TypeScript-first with full type safety
  • 🚀 Perfect for "git clone && npm install && npm start" projects
  • 👀 Easy to inspect and debug (it's just JSON!)
  • 📦 Tiny footprint with minimal dependencies

Installation

# npm
npm install octavedb

# pnpm
pnpm add octavedb

# yarn
yarn add octavedb

Quick Start

1. Create your database types

// types.ts
import { Resource } from 'octavedb';

export interface User extends Resource {
  username: string;
  email: string;
}

export interface Post extends Resource {
  title: string;
  content: string;
  userId: User['id'];
}

export interface Database {
  users: User[];
  posts: Post[];
}

The Resource interface automatically adds:

  • id: string - Unique identifier
  • createdAt: string - ISO timestamp
  • updatedAt: string - ISO timestamp

2. Create an empty JSON file

{
  "users": [],
  "posts": []
}

3. Initialize the client

// lib/db.ts
import { createClient } from 'octavedb';
import type { Database } from './types';

export const db = createClient<Database>('./database.json');

// Also export the helpers for convenience
export { makeResource, makeDateTime, makeId } from 'octavedb';

4. Use it!

import { db, makeResource, makeDateTime } from './lib/db';
import type { User } from './types';

// CREATE
function createUser(username: string, email: string): User {
  const data = db.read();
  
  const exists = data.users.some(u => u.username === username);
  if (exists) throw new Error('Username already exists');
  
  const user = makeResource<User>({ username, email });
  data.users.push(user);
  db.write(data);
  
  return user;
}

// READ
function getUser(id: string): User {
  const data = db.read();
  const user = data.users.find(u => u.id === id);
  
  if (!user) throw new Error('User not found');
  return user;
}

// UPDATE
function updateUserEmail(id: string, email: string): User {
  const data = db.read();
  const index = data.users.findIndex(u => u.id === id);
  
  if (index < 0) throw new Error('User not found');
  
  data.users[index] = {
    ...data.users[index],
    email,
    updatedAt: makeDateTime()
  };
  db.write(data);
  
  return data.users[index];
}

// DELETE
function removeUser(id: string): User {
  const data = db.read();
  const index = data.users.findIndex(u => u.id === id);
  
  if (index < 0) throw new Error('User not found');
  
  const deleted = data.users.splice(index, 1)[0];
  db.write(data);
  
  return deleted;
}

API Reference

createClient<Database>(filePath: string)

Creates a database client for the specified JSON file.

const db = createClient<Database>('./database.json');

db.read(): Database

Reads and returns the entire database.

const data = db.read();
console.log(data.users);

db.write(data: Database): void

Writes data to the database file atomically.

const data = db.read();
data.users.push(newUser);
db.write(data);

makeResource<T>(data): T & Resource

Creates a new resource with automatic id, createdAt, and updatedAt fields.

const user = makeResource<User>({
  username: 'john',
  email: '[email protected]'
});
// Returns: { id: '...', createdAt: '...', updatedAt: '...', username: 'john', email: '...' }

Helper Functions

makeId()        // Returns a UUID v4 string
makeDateTime()  // Returns current ISO timestamp string

Advanced: Custom Resource Types

If you don't want the default createdAt/updatedAt fields:

// Minimal resource with just ID
export interface MinimalUser extends Pick<Resource, 'id'> {
  username: string;
}

// Or create your own base interface
export interface CustomBase {
  id: string;
  timestamp: number;
}

export interface CustomUser extends CustomBase {
  username: string;
}

Note: When using custom resource types, you'll need to handle ID/timestamp generation manually.

How it Works

OctaveDB uses atomic file writes to prevent corruption:

  1. Writes data to a temporary file
  2. Atomically renames temp file to actual database file
  3. Ensures your database is never left in a half-written state

All data is stored as pretty-printed JSON for easy inspection and debugging.

License

MIT

Contributing

Issues and pull requests welcome!