
Research
/Security News
Mini Shai-Hulud Campaign Hits Red Hat Cloud Services npm Packages
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.
@hazeljs/rag
Advanced tools
Retrieval-Augmented Generation (RAG) and vector search for HazelJS framework
Your docs. Your data. AI that actually knows them.
Part of the HazelJS AI-Native Backend Framework. Load documents from any source, build a knowledge graph, embed into vector stores, and retrieve answers with semantic, hybrid, or graph-based search. Full RAG + GraphRAG pipeline — no PhD required.
🚀 Trusted by 200K+ monthly downloads • 37+ GitHub stars • 15+ daily active developers
Built for AI-native applications - not just another RAG library. When you combine @hazeljs/rag with @hazeljs/core, @hazeljs/ai, and @hazeljs/agent, you get a complete stack for intelligent backends.
Perfect for:
Document[] interface.npm install @hazeljs/rag
Install only what you need:
# LLM (required for GraphRAG and RAG query synthesis)
npm install openai
# Vector stores
npm install @pinecone-database/pinecone # Pinecone
npm install @qdrant/js-client-rest # Qdrant
npm install weaviate-ts-client # Weaviate
npm install chromadb # ChromaDB
# Alternative embedding providers
npm install cohere-ai
# Document loaders
npm install pdf-parse # PdfLoader
npm install mammoth # DocxLoader
npm install cheerio # HtmlFileLoader / WebLoader CSS selectors
# Memory backend (for createHazelMemoryStoreAdapter from @hazeljs/rag/memory-hazel)
npm install @hazeljs/memory
import {
RAGPipeline,
MemoryVectorStore,
OpenAIEmbeddings,
RecursiveTextSplitter,
DirectoryLoader,
} from '@hazeljs/rag';
const embeddings = new OpenAIEmbeddings({ apiKey: process.env.OPENAI_API_KEY });
const vectorStore = new MemoryVectorStore(embeddings);
const rag = new RAGPipeline({
vectorStore,
embeddingProvider: embeddings,
textSplitter: new RecursiveTextSplitter({ chunkSize: 800, chunkOverlap: 150 }),
topK: 5,
});
await rag.initialize();
// Load from disk — auto-detects file types
const docs = await new DirectoryLoader({ dirPath: './knowledge-base', recursive: true }).load();
await rag.addDocuments(docs);
const result = await rag.query('What is HazelJS?', { topK: 3 });
console.log(result.answer);
console.log(result.sources);
Every loader extends BaseDocumentLoader and returns Document[] ready for chunking and indexing.
| Loader | Source | Extra install |
|---|---|---|
TextFileLoader | .txt files | — |
MarkdownFileLoader | .md / .mdx with heading splits and YAML front-matter | — |
JSONFileLoader | .json with textKey / JSON Pointer extraction | — |
CSVFileLoader | .csv rows mapped to documents | — |
HtmlFileLoader | .html tag stripping; optional CSS selector via cheerio | opt. |
DirectoryLoader | Recursive walk; auto-detects loader by extension | — |
PdfLoader | PDFs; split by page or full document | pdf-parse |
DocxLoader | Word documents; plain text or HTML output | mammoth |
WebLoader | HTTP scraping with retry/timeout; optional CSS selector | opt. |
YouTubeTranscriptLoader | YouTube transcripts; no API key; segment by duration | — |
GitHubLoader | GitHub REST API; filter by path, extension, maxFiles | — |
import {
TextFileLoader,
MarkdownFileLoader,
JSONFileLoader,
CSVFileLoader,
PdfLoader,
DocxLoader,
WebLoader,
YouTubeTranscriptLoader,
GitHubLoader,
DirectoryLoader,
} from '@hazeljs/rag';
// Plain text
const textDocs = await new TextFileLoader({ filePath: './notes.txt' }).load();
// Markdown — one document per heading section
const mdDocs = await new MarkdownFileLoader({
filePath: './guide.md',
splitByHeading: true,
parseYamlFrontMatter: true,
}).load();
// JSON — extract the 'body' field from each element
const jsonDocs = await new JSONFileLoader({ filePath: './articles.json', textKey: 'body' }).load();
// CSV — map columns to content / metadata
const csvDocs = await new CSVFileLoader({
filePath: './faqs.csv',
contentColumns: ['question', 'answer'],
metadataColumns: ['category'],
}).load();
// PDF — one document per page
const pdfDocs = await new PdfLoader({ filePath: './report.pdf', splitByPage: true }).load();
// DOCX
const wordDocs = await new DocxLoader({ filePath: './agreement.docx' }).load();
// Web scraping
const webDocs = await new WebLoader({
urls: ['https://hazeljs.ai/docs', 'https://hazeljs.ai/blog'],
timeout: 10_000,
maxRetries: 3,
}).load();
// YouTube transcript (no API key needed)
const ytDocs = await new YouTubeTranscriptLoader({
videoUrl: 'https://www.youtube.com/watch?v=VIDEO_ID',
segmentDuration: 60, // group into 60-second chunks
}).load();
// GitHub repository
const githubDocs = await new GitHubLoader({
owner: 'hazeljs',
repo: 'hazel',
directory: 'docs',
extensions: ['.md'],
token: process.env.GITHUB_TOKEN,
}).load();
// Directory — auto-detects every file type
const allDocs = await new DirectoryLoader({
dirPath: './knowledge-base',
recursive: true,
extensions: ['.md', '.txt', '.pdf'],
}).load();
import { BaseDocumentLoader, Loader, DocumentLoaderRegistry } from '@hazeljs/rag';
@Loader({ name: 'NotionLoader', extensions: [] })
export class NotionLoader extends BaseDocumentLoader {
constructor(private readonly databaseId: string) {
super();
}
async load() {
const pages = await fetchNotionPages(this.databaseId);
return pages.map((p) =>
this.createDocument(p.content, { source: `notion:${p.id}`, title: p.title })
);
}
}
// Register so DirectoryLoader can auto-detect it
DocumentLoaderRegistry.register(NotionLoader, (id: string) => new NotionLoader(id));
GraphRAG builds a knowledge graph from your documents — entities, relationships, and community clusters — and enables three complementary search modes that go far beyond cosine similarity.
| Question type | Traditional RAG | GraphRAG |
|---|---|---|
| "What does X do?" | ✅ Good | ✅ Excellent (entity traversal) |
| "How do X and Y relate?" | ❌ Poor | ✅ Excellent (relationships) |
| "What are the main architectural layers?" | ❌ Poor | ✅ Excellent (community reports) |
| Multi-document cross-referencing | ❌ Fragmented | ✅ Native |
import OpenAI from 'openai';
import { GraphRAGPipeline, DirectoryLoader } from '@hazeljs/rag';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const graphRag = new GraphRAGPipeline({
// Provider-agnostic: any LLM that accepts a string prompt
llm: async (prompt) => {
const res = await openai.chat.completions.create({
model: 'gpt-4o-mini',
temperature: 0,
messages: [{ role: 'user', content: prompt }],
});
return res.choices[0].message.content ?? '';
},
extractionChunkSize: 2000, // chars per LLM extraction call
generateCommunityReports: true, // LLM summaries per community cluster
maxCommunitySize: 15, // split clusters larger than this
localSearchDepth: 2, // BFS hops for local search
localSearchTopK: 5, // seed entities per query
globalSearchTopK: 5, // community reports for global search
});
const docs = await new DirectoryLoader({ dirPath: './knowledge-base', recursive: true }).load();
const stats = await graphRag.build(docs);
// { documentsProcessed, entitiesExtracted, relationshipsExtracted,
// communitiesDetected, communityReportsGenerated, duration }
// LOCAL — entity-centric, BFS graph traversal
// Best for: specific questions about named concepts, classes, or technologies
const local = await graphRag.search('How does dependency injection work?', { mode: 'local' });
console.log(local.answer);
console.log(local.entities); // entities found and traversed
console.log(local.relationships); // evidence relationships
// GLOBAL — community report ranking
// Best for: broad thematic questions, architecture overviews
const global = await graphRag.search('What are the main architectural layers of this system?', {
mode: 'global',
});
console.log(global.communities); // ranked community reports used
// HYBRID — runs both in parallel, single synthesis call (recommended default)
const result = await graphRag.search('What vector stores does @hazeljs/rag support?');
// mode defaults to 'hybrid'
console.log(`${result.mode} search in ${result.duration}ms`);
const newDocs = await new WebLoader({ urls: ['https://hazeljs.ai/blog/new'] }).load();
await graphRag.addDocuments(newDocs);
// Re-runs community detection and regenerates reports automatically
const graph = graphRag.getGraph();
// Entities, relationships, community reports
console.log([...graph.entities.values()].slice(0, 5));
console.log([...graph.relationships.values()].slice(0, 5));
console.log([...graph.communityReports.values()].map((r) => r.title));
// Statistics
const stats = graphRag.getStats();
console.log(stats.entityTypeBreakdown); // { TECHNOLOGY: 14, CONCEPT: 12, ... }
console.log(stats.topEntities.slice(0, 5)); // most-connected entities
All stores implement the same interface — swap them with a one-line change.
import { MemoryVectorStore, OpenAIEmbeddings } from '@hazeljs/rag';
// Development
const vectorStore = new MemoryVectorStore(embeddings);
// Pinecone (production, serverless)
import { PineconeVectorStore } from '@hazeljs/rag';
const vectorStore = new PineconeVectorStore(embeddings, {
apiKey: process.env.PINECONE_API_KEY,
indexName: 'my-knowledge-base',
});
// Qdrant (high-performance, self-hosted)
import { QdrantVectorStore } from '@hazeljs/rag';
const vectorStore = new QdrantVectorStore(embeddings, {
url: process.env.QDRANT_URL || 'http://localhost:6333',
collectionName: 'my-collection',
});
// Weaviate (GraphQL, flexible)
import { WeaviateVectorStore } from '@hazeljs/rag';
const vectorStore = new WeaviateVectorStore(embeddings, {
host: process.env.WEAVIATE_HOST || 'http://localhost:8080',
className: 'MyKnowledgeBase',
});
// ChromaDB (prototyping)
import { ChromaVectorStore } from '@hazeljs/rag';
const vectorStore = new ChromaVectorStore(embeddings, {
url: process.env.CHROMA_URL || 'http://localhost:8000',
collectionName: 'my-collection',
});
| Memory | Pinecone | Qdrant | Weaviate | ChromaDB | |
|---|---|---|---|---|---|
| Setup | None | API Key | Docker | Docker | Docker |
| Persistence | ❌ | ✅ | ✅ | ✅ | ✅ |
| Best for | Dev/Test | Production | High-perf | GraphQL | Prototyping |
| Cost | Free | Paid | OSS | OSS | OSS |
import { OpenAIEmbeddings, CohereEmbeddings } from '@hazeljs/rag';
// OpenAI
const openaiEmbed = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: 'text-embedding-3-small', // 1536 dims
// model: 'text-embedding-3-large', // 3072 dims, highest quality
});
// Cohere (multilingual)
const cohereEmbed = new CohereEmbeddings({
apiKey: process.env.COHERE_API_KEY,
model: 'embed-multilingual-v3.0',
});
import { HybridSearchRetrieval, MultiQueryRetrieval } from '@hazeljs/rag';
// Hybrid — vector + BM25 keyword fusion
const hybrid = new HybridSearchRetrieval(vectorStore, {
vectorWeight: 0.7,
keywordWeight: 0.3,
topK: 10,
});
const results = await hybrid.search('machine learning algorithms', { topK: 5 });
// Multi-query — LLM generates N query variations, deduplicates results
const multiQuery = new MultiQueryRetrieval(vectorStore, {
llmApiKey: process.env.OPENAI_API_KEY,
numQueries: 3,
topK: 10,
});
const results2 = await multiQuery.search('How do I deploy my app?', { topK: 5 });
import { RecursiveTextSplitter } from '@hazeljs/rag';
const splitter = new RecursiveTextSplitter({
chunkSize: 1000, // target chars per chunk
chunkOverlap: 200, // overlap for context continuity
separators: ['\n\n', '\n', '. ', ' '],
});
const chunks = splitter.split(longDocument);
import {
RAGPipelineWithMemory,
MemoryManager,
HybridMemory,
BufferMemory,
VectorMemory,
} from '@hazeljs/rag';
const buffer = new BufferMemory({ maxSize: 20 });
const vectorMemory = new VectorMemory(vectorStore, embeddings);
const memory = new MemoryManager(new HybridMemory(buffer, vectorMemory));
const rag = new RAGPipelineWithMemory(config, memory, llmFunction);
const response = await rag.queryWithMemory(
'What did we discuss about deployment?',
'session-123',
'user-456'
);
console.log(response.answer);
console.log(response.memories);
To back RAG (and agent) memory with @hazeljs/memory (in-memory, Prisma, Redis, etc.) in-process, install the optional peer and use the adapter:
npm install @hazeljs/memory
import { MemoryManager, RAGPipelineWithMemory } from '@hazeljs/rag';
import { createHazelMemoryStoreAdapter } from '@hazeljs/rag/memory-hazel';
import { MemoryService, createDefaultMemoryStore } from '@hazeljs/memory';
// One store and one MemoryManager at app level (in-process, no separate service)
const hazelStore = createDefaultMemoryStore();
const memoryService = new MemoryService(hazelStore);
const ragStore = createHazelMemoryStoreAdapter(memoryService);
const memoryManager = new MemoryManager(ragStore);
// Pass the same MemoryManager to RAG and to every AgentRuntime for shared memory
const rag = new RAGPipelineWithMemory(config, memoryManager, llmFunction);
// agentRuntime = new AgentRuntime({ ..., memoryManager });
MemoryManager once, then pass the same instance into RAGPipelineWithMemory and every AgentRuntime.createPrismaMemoryStore (or the appropriate factory) from @hazeljs/memory and pass it to MemoryService before wrapping with createHazelMemoryStoreAdapter.GraphRAGPipelineclass GraphRAGPipeline {
constructor(config: GraphRAGConfig);
build(docs: Document[]): Promise<GraphBuildStats>;
addDocuments(docs: Document[]): Promise<GraphBuildStats>;
search(query: string, options?: GraphSearchOptions): Promise<GraphSearchResult>;
getGraph(): KnowledgeGraph;
getStats(): GraphStats;
clear(): void;
}
RAGPipelineclass RAGPipeline {
constructor(config: RAGConfig, llmFunction?: LLMFunction);
initialize(): Promise<void>;
addDocuments(documents: Document[]): Promise<string[]>;
query(query: string, options?: RAGQueryOptions): Promise<RAGResponse>;
search(query: string, options?: QueryOptions): Promise<SearchResult[]>;
deleteDocuments(ids: string[]): Promise<void>;
clear(): Promise<void>;
}
Documentinterface Document {
id?: string;
content: string;
metadata?: Record<string, unknown>;
embedding?: number[];
}
Apache 2.0
Contributions are welcome! See CONTRIBUTING.md for details.
FAQs
Retrieval-Augmented Generation (RAG) and vector search for HazelJS framework
We found that @hazeljs/rag 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.

Research
/Security News
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.

Research
/Security News
The North Korean malware loader hides in a Packagist-listed package and its GitHub branch to fetch and execute remote code in a likely Contagious Interview-style lure.

Security News
The Rust project is moving toward formal rules on LLM use in contributions after months of internal debate over maintainer burden, code quality, and contributor experience.