octavedb
v1.0.0
Published
A simple, TypeScript-first JSON file database for local development and prototyping
Maintainers
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 octavedbQuick 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 identifiercreatedAt: string- ISO timestampupdatedAt: 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 stringAdvanced: 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:
- Writes data to a temporary file
- Atomically renames temp file to actual database file
- 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!
