
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
A storage library using LSM trees for storage and B-trees for indices with MVCC support
Indinis is a high-performance, embedded NoSQL database for Node.js and TypeScript, featuring a fluent, Firestore-like API. It's designed to be fast, easy to use, and powerful enough for complex applications.
Install Indinis via npm:
npm i indinis
arrayContains, arrayContainsAny).npm install indinis
Here's a simple example to get you up and running in minutes.
import { Indinis } from 'indinis';
// Define a type for your data for type-safety
interface User {
id?: string;
name: string;
email: string;
createdAt: number;
}
async function main() {
// 1. Initialize the database
const db = new Indinis('./my-first-database');
const usersStore = db.store<User>('users');
// 2. Create a new user with an auto-generated ID
console.log('Creating a new user...');
const newUser = await usersStore.make({
name: 'Alice',
email: 'alice@example.com',
createdAt: Date.now()
}).withSnapshot(); // .withSnapshot() returns the full document
console.log('User created:', newUser);
// 3. Read the user back by their ID
console.log('\nFetching user by ID...');
const fetchedUser = await usersStore.item(newUser.id!).one();
console.log('Found:', fetchedUser);
// 4. Query for the user by their email
console.log('\nQuerying for user by email...');
const userFromQuery = await usersStore
.filter('email').equals('alice@example.com')
.one();
console.log('Found via query:', userFromQuery);
}
main().catch(console.error);
Indinis organizes data in a hierarchical structure familiar to users of document databases.
'users', 'users/user123/posts').'users/user123').import { Indinis } from 'indinis';
const db = new Indinis('./my-database');
// A reference to the top-level 'users' store
const usersStore = db.store('users');
// A reference to a specific user item
const userItem = usersStore.item('user123');
// A reference to a nested 'posts' store for a user
const userPostsStore = db.store('users/user123/posts');
Use .make() to create or overwrite documents.
Call .make() on a StoreRef to create a document with a unique, auto-generated ID.
const users = db.store('users');
// By default, make() resolves with the new document's ID
const newUserId = await users.make({
name: 'John Doe',
email: 'john.doe@example.com'
});
console.log('Created user with ID:', newUserId);
// Chain .withSnapshot() to get the full document back immediately
const newUserDoc = await users.make({
name: 'Jane Smith',
email: 'jane.smith@example.com'
}).withSnapshot();
console.log('Created new user:', newUserDoc);
// { name: 'Jane Smith', ..., id: 'bH5iLr9tMq0xZaZ4wH3v' }
Call .make() on an ItemRef to create a document with an ID you provide. By default, this fails if the document already exists to prevent accidental overwrites.
const userItem = db.store('users').item('john-doe-123');
await userItem.make({ name: 'John Doe', email: 'john@example.com' });
// To overwrite an existing document, pass `true` as the second argument.
await userItem.make({ name: 'John Doe V2', status: 'active' }, true);
The most direct way to get a document is by its ID using item(...).one().
const userData = await db.store('users').item('john-doe-123').one();
if (userData) {
console.log(userData.name); // 'John Doe V2'
}
You can also efficiently check for existence with .exists().
const userExists = await db.store('users').item('john-doe-123').exists(); // true or false
modify()Use .modify() on an ItemRef to update specific fields of a document without replacing the entire object. This method will fail if the document does not exist.
const userItem = db.store('users').item('john-doe-123');
// Update the user's status and add a new 'lastLogin' field
await userItem.modify({
status: 'active',
lastLogin: Date.now()
});
For counters (likes, views, etc.), use the atomic increment() operator to prevent race conditions. Import the increment function from the indinis library.
Rules: The target field must exist and its value must be a number.
import { Indinis, increment } from 'indinis';
const postRef = db.store('posts').item('postXYZ');
// Atomically increment 'views' and update 'lastViewedBy' in one operation
await postRef.modify({
views: increment(1),
lastViewedBy: 'user-abc'
});
// You can also
await db.store('users').item('user123').remove();
Build queries by starting with a store() or query() and chaining methods.
.filter()Use .filter() with a chainable operator to define your query conditions.
| Operator | Description |
|---|---|
.equals(val) | Field is equal to val |
.greaterThan(val) | Field is greater than val |
.greaterThanOrEqual(val) | Field is >= val |
.lessThan(val) | Field is less than val |
.lessThanOrEqual(val) | Field is <= val |
You can chain multiple .filter() calls. For a query to succeed, at least one of the filtered fields must be indexed.
const activeEngineers = await db.store<Employee>('employees')
.filter('department').equals('eng') // Uses an index
.filter('status').equals('active') // Post-filtered in memory
.filter('level').greaterThanOrEqual(5) // Post-filtered in memory
.take(10); // Retrieves up to 10 matching documents
Indinis supports powerful queries on array fields, provided a multikey index exists on the field.
// Create an index on the 'tags' array field for the 'products' store
await db.createIndex('products', 'idx_prod_tags', {
field: 'tags',
multikey: true
});
arrayContainsFind documents where the array field contains a specific element.
// Find all products tagged as 'electronics'
const electronics = await db.store('products')
.filter('tags').arrayContains('electronics')
.take();
arrayContainsAnyFind documents where the array field contains at least one of the elements from the provided list.
// Find products that are on 'sale' OR are a 'bestseller'
const featured = await db.store('products')
.filter('tags').arrayContainsAny(['sale', 'bestseller'])
.take();
.sortBy()Use .sortBy() to order your query results. Sorting requires an index on the field you are sorting by.
const recentUsers = await db.store('users')
.sortBy('createdAt', 'desc') // Sort by creation date, newest first
.take(20);
Indinis provides efficient, cursor-based pagination. Pagination queries must include at least one .sortBy() clause.
The .get() method executes the query and returns a PaginatedQueryResult object containing the documents, cursors, and page information.
const usersStore = db.store('users');
const PAGE_SIZE = 10;
// --- Fetch the First Page ---
const firstPage = await usersStore.query()
.sortBy('name', 'asc')
.limit(PAGE_SIZE)
.get();
console.log('First page users:', firstPage.docs.map(u => u.name));
console.log('Has next page?', firstPage.hasNextPage);
// --- Fetch the Next Page ---
if (firstPage.hasNextPage) {
const nextPage = await usersStore.query()
.sortBy('name', 'asc') // The query must be identical
.limit(PAGE_SIZE)
.startAfter(...firstPage.endCursor!) // Use the cursor from the previous page
.get();
console.log('Next page users:', nextPage.docs.map(u => u.name));
}
Indinis includes an optional in-memory cache to dramatically accelerate read-heavy workloads. The cache operates transparently using a cache-aside pattern: items are cached on first read, and automatically invalidated on any write (set, modify, remove) to guarantee consistency.
Enable the cache via IndinisOptions.
import { Indinis, IndinisOptions } from 'indinis';
const dbOptions: IndinisOptions = {
enableCache: true, // Simple enablement with defaults
// Advanced configuration
cacheOptions: {
maxSize: 5000, // Max items in cache (default: 1000)
policy: 'LRU', // Eviction policy: 'LRU' or 'LFU'
defaultTTLMilliseconds: 60000, // Expire entries after 1 minute (default: 0, no TTL)
enableStats: true // Set true to monitor performance
}
};
const db = new Indinis('./my-cached-db', dbOptions);
Use db.getCacheStats() to check the cache's effectiveness. The most important metric is the hitRate.
const stats = await db.getCacheStats();
if (stats) {
console.log(`Cache Hit Rate: ${(stats.hitRate * 100).toFixed(2)}%`);
}
Indinis is designed for performance and will not perform slow, un-indexed collection scans.
Rule: No Index, No Query. A query with one or more .filter() conditions must be serviceable by at least one existing index. If no suitable index is found, the operation will throw an error.
name IndexFor convenience, the first time a document is written to a new store, Indinis automatically creates a default secondary index on the name field. This allows you to start querying immediately on new collections.
You can see which indexes are available for a specific collection.
const userIndexes = await db.store('users').listIndexes();
console.log(userIndexes);
.use()For complex applications, you can encapsulate and reuse query logic using .use(). Define reusable parts as functions that take and return a Query object.
import { IQuery } from 'indinis';
// A reusable part to find only active users
const isActive = (query: IQuery<User>) => query.filter('status').equals('active');
// A parameterized part to find users by region
const byRegion = (region: string) =>
(query: IQuery<User>) => query.filter('region').equals(region);
// Compose the parts to build a clean, readable query
const recentActiveWestCoastUsers = await db.store<User>('users')
.query() // Start a composable query
.use(isActive)
.use(byRegion('us-west'))
.sortBy('createdAt', 'desc')
.take(20);
You can customize the database behavior by passing an IndinisOptions object to the constructor.
import { Indinis, IndinisOptions } from 'indinis';
const dbOptions: IndinisOptions = {
enableCache: true,
cacheOptions: {
maxSize: 10000
},
// ... other options
};
const db = new Indinis('./my-database', dbOptions);
FAQs
A storage library using LSM trees for storage and B-trees for indices with MVCC support
The npm package indinis receives a total of 16 weekly downloads. As such, indinis popularity was classified as not popular.
We found that indinis demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.