QuickstartNode / TypeScript

Quickstart — Node / TypeScript

When you’re already running a Node app and you don’t want another process, embed Mnemosyne directly. @mnemosyne/core is the same engine the standalone server uses — just imported as a library.

Install

pnpm add @mnemosyne/core @mnemosyne/client-ts

Point it at a Postgres

mnemo.ts
import { createMnemoClient, createDrizzleStorage } from "@mnemosyne/core";
 
const storage = createDrizzleStorage({
  databaseUrl: process.env.DATABASE_URL!, // postgres://...
  applyMigrations: true,                  // safe to call on boot
});
 
export const mnemo = createMnemoClient({ storage });

The first call applies every migration to your Postgres if they aren’t already there. Subsequent boots are a no-op.

Remember + recall

await mnemo.remember({
  workspaceId: "demo",
  content: "Lucas prefers espresso to filter coffee",
  tags: ["preferences", "coffee"],
});
 
const hits = await mnemo.recall({
  workspaceId: "demo",
  query: "coffee preferences",
  topK: 3,
});
 
console.log(hits);

Drop the API on a route (optional)

If you want other services to talk HTTP, mount @mnemosyne/server on the same process:

app.ts
import { Hono } from "hono";
import { mountMnemosyne } from "@mnemosyne/server";
 
const app = new Hono();
mountMnemosyne(app, { client: mnemo, basePath: "/v1" });
export default app;

Now your existing app exposes /v1/facts, /v1/recall, etc., with the same behaviour as the standalone server.

Embedded vs sidecar vs standalone

ModeWhen to pick it
EmbeddedOne Node app, one process, in-process function calls. Lowest latency.
SidecarSame VM, separate process, talks HTTP on localhost. Decoupled deploys.
StandaloneMulti-VM, multi-tenant, talks HTTP across the network. Shared instance.

The data layer is identical. Switching modes is a config change.

Optional: enable embeddings

import { createOpenAIEmbedder } from "@mnemosyne/llm-providers";
 
export const mnemo = createMnemoClient({
  storage,
  // BYO key. Pass any provider with the right signature — OpenAI, Voyage,
  // Cohere, a local Ollama, or your own function.
  embedder: createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! }),
});

Mnemosyne never reads OPENAI_API_KEY on its own — you wire it in explicitly. That keeps credentials owned by your app, not by Mnemosyne.

💡

Don’t have an embeddings provider? Skip this step. Recall falls back to full-text search and stays useful. You can enable vectors later without data loss.