Skip to content

Memory Plugin ​

The Memory Plugin provides fast, in-memory data storage for your Routier application.

Quick Navigation ​

Overview ​

The Memory Plugin is the fastest storage option in Routier, storing all data in RAM for instant access. It's perfect for development, testing, and high-performance applications.

Installation ​

bash
npm install @routier/memory-plugin

Basic Usage ​

ts
import { DataStore } from "@routier/datastore";
import { s } from "@routier/core/schema";
import { MemoryPlugin } from "@routier/memory-plugin";

const userSchema = s
    .define("users", {
        id: s.string().key().identity(),
        email: s.string().distinct(),
        name: s.string(),
        createdAt: s.date().default(() => new Date()),
    })
    .compile();

class Ctx extends DataStore {
    users = this.collection(userSchema).proxy().create();

    constructor() {
        super(new MemoryPlugin("app"));
    }
}

const ctx = new Ctx();
await ctx.users.addAsync({ name: "James", email: "[email protected]" });
await ctx.saveChangesAsync();

Configuration ​

Constructor Parameters ​

ts
import { MemoryPlugin } from "@routier/memory-plugin";

const memoryPlugin = new MemoryPlugin(
  "my-app" // Database name (optional). Omit it to use the shared default database.
);

Database Name ​

The database name identifies the database, the same way a file path identifies a SQLite database. Use a distinct name for separate data, and reuse a name deliberately when stores should share data. If you omit the name, the plugin uses a fixed default name, so every unnamed instance shares one database. See Shared Named Databases.

ts
import { DataStore } from "@routier/datastore";
import { MemoryPlugin } from "@routier/memory-plugin";

// Different names are different databases
const userContext = new DataStore(new MemoryPlugin("users"));
const orderContext = new DataStore(new MemoryPlugin("orders"));

// The same name is the same database: records saved through one store are visible to the other
const tabOne = new DataStore(new MemoryPlugin("app"));
const tabTwo = new DataStore(new MemoryPlugin("app"));

Performance Characteristics ​

Advantages ​

  • Instant access - No I/O delays
  • High throughput - Can handle thousands of operations per second
  • Low latency - Sub-millisecond response times
  • No serialization overhead - Data stays in memory

Limitations ​

  • Memory usage - All data must fit in RAM
  • No persistence - Data is lost when application restarts
  • No cross-process sharing - Separate processes, workers, and browser tabs each hold their own databases, even with the same name. Within one process, instances with the same name share data (see Shared Named Databases)

Use Cases ​

Development and Testing ​

ts
import { DataStore } from "@routier/datastore";
import { MemoryPlugin } from "@routier/memory-plugin";

// Perfect for unit tests
class TestContext extends DataStore {
  constructor() {
    super(new MemoryPlugin("test"));
  }
}

High-Performance Applications ​

ts
import { DataStore } from "@routier/datastore";
import { MemoryPlugin } from "@routier/memory-plugin";

// For applications requiring maximum speed
class PerformanceContext extends DataStore {
  constructor() {
    super(new MemoryPlugin("performance"));
  }
}

Offline-First with Sync ​

ts
import { MemoryPlugin } from "@routier/memory-plugin";
import { PouchDbPlugin } from "@routier/pouchdb-plugin";
import { ReplicationDbPlugin } from "@routier/core/plugins";

const memoryPlugin = new MemoryPlugin("offline");
const pouchDbPlugin = new PouchDbPlugin("remote");

const replicationPlugin = new ReplicationDbPlugin({
  replicas: [memoryPlugin],
  source: pouchDbPlugin,
  read: memoryPlugin,
});

API Reference ​

Constructor ​

ts
import { MemoryPlugin } from "@routier/memory-plugin";

new MemoryPlugin(databaseName?: string)

// Constructor
// @param databaseName - Name of the in-process database to connect to. Instances with the same
//                       name share one database. Defaults to "__routier-memory-plugin-db__", so
//                       every unnamed instance shares the same default database.

Properties ​

  • databaseName - The name of the database

Methods ​

The Memory Plugin implements all standard plugin methods:

  • add() - Add entities to collections
  • update() - Update existing entities
  • remove() - Remove entities
  • query() - Query collections
  • destroy() - Clear the named database

Shared Named Databases ​

The name addresses a database; it is not a label for the plugin instance. The plugin keeps one database per NAME, shared by every MemoryPlugin instance in the same JavaScript process. This is intended, and it mirrors how other databases work: two plugins pointing at the same SQLite file or PostgreSQL database are two connections to the same data.

  • Same name, same data - Two new MemoryPlugin("app") instances read and write the same records. A different name is a different, empty database.
  • Unnamed instances share too - new MemoryPlugin() uses a fixed default name, so every unnamed instance connects to the same default database.
  • Reads are copies - Each store gets its own copies of records, never shared object references. Only saved changes cross stores: an unsaved edit in one store is invisible to another, and mutating a returned object without saving does not change stored data.
  • Live queries follow the database - A subscription in one store updates when another store saves to the same-named database.
  • destroy() affects every instance - It clears the named database for every user of that name, not only for the instance you call it on.
  • One process only - Separate processes, workers, and browser tabs hold separate databases.

Sharing a name is how you model several stores on one database, such as the tabs of a multi-tab app in a single test. When tests should not see each other's data, give each test its own database name:

ts
const store = new AppStore(new MemoryPlugin(`test-${crypto.randomUUID()}`));

Next Steps ​

Released under the MIT License.