If you're building with ArangoDB and TypeScript, you've probably wished for a Mongoose-like experience with full type safety. Meet arango-typed — a production-ready ORM/ODM/OGM that brings a familiar API to ArangoDB with enterprise-grade features.
What is arango-typed?
arango-typed is a comprehensive, type-safe database abstraction layer for ArangoDB that combines:
- ORM (Object Relational Mapping)
- ODM (Object Document Mapping)
- OGM (Object Graph Mapper)
All in one package, with end-to-end type safety and a Mongoose-like API that makes ArangoDB development as intuitive as working with MongoDB.
Why arango-typed?
Working with ArangoDB's native driver can be verbose and lacks the developer experience of popular ORMs. arango-typed solves this by providing:
✅ Full TypeScript Support - Type-safe from database to API
✅ Mongoose-like API - Familiar developer experience
✅ Production-Ready Features - Multi-tenancy, audit tracking, soft delete
✅ Graph Database Native - First-class support for edges, vertices, and relationships
✅ Vector Search & AI - Built-in LangChain integration for RAG applications
✅ Performance Optimized - Only ~10-15% overhead vs raw driver
✅ Framework Agnostic - Works with Express, Fastify, Koa, NestJS, Next.js, Hono
Quick Start
Installation
npm install arango-typed arangojs
Basic Usage
import { connect, Schema, model } from 'arango-typed';
// Connect to ArangoDB (Mongoose-like API)
await connect('http://localhost:8529/myapp', {
username: 'root',
password: ''
});
// Define Schema (Mongoose-like shorthand)
const userSchema = new Schema({
name: String, // Simple shorthand
email: { type: String, required: true, unique: true }, // With options
age: Number,
createdAt: { type: Date, default: () => new Date() }
});
// Create Model
const User = model('users', userSchema);
// Use the Model
const user = await User.create({
name: 'John Doe',
email: 'john@example.com',
age: 30
});
console.log(user.name); // TypeScript knows this is a string!
Key Features
1. Production-Ready Multi-Tenancy
Build SaaS applications with automatic tenant isolation:
import express from 'express';
import { tenantMiddleware } from 'arango-typed/integrations/express';
const app = express();
// Extract tenant from header (default: 'x-tenant-id')
app.use(tenantMiddleware({ extractFrom: 'header' }));
// Enable multi-tenancy on model
const User = model('users', userSchema, { tenantEnabled: true });
// Automatically filtered by tenant!
app.get('/users', async (req, res) => {
const users = await User.find({}); // Only current tenant's users
res.json(users);
});
app.post('/users', async (req, res) => {
// Tenant ID automatically injected
const user = await User.create(req.body);
res.json(user);
});
Benefits:
- Automatic tenant filtering on all queries
- Automatic tenant injection on create
- Works seamlessly with Express, Fastify, Koa, and more
- Zero configuration needed
2. Comprehensive Audit Functionality
Track who created, updated, or deleted documents with automatic audit logging:
import { AuditContext } from 'arango-typed';
// Set user context (typically in Express middleware)
AuditContext.set('user123', {
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0'
});
// Enable audit on model
const User = model('users', userSchema, {
auditEnabled: true
});
// Create - automatically adds createdBy, createdAt, updatedBy, updatedAt
const user = await User.create({ name: 'John' });
// user.createdBy = 'user123'
// user.createdAt = Date
// user.updatedBy = 'user123'
// user.updatedAt = Date
// Update - automatically updates updatedBy, updatedAt and logs changes
await user.update({ name: 'Jane' });
// Get audit logs
const logs = await User.getAuditLogs(user._id);
const userLogs = await User.getAuditLogsByUser('user123');
const createLogs = await User.getAuditLogsByAction('create');
Use Cases:
- Compliance and regulatory requirements
- Debugging and troubleshooting
- User activity tracking
- Change history and rollback
3. Soft Delete with Restore
Mark documents as deleted without actually removing them:
// Enable soft delete
const User = model('users', userSchema, {
softDeleteEnabled: true
});
// Create a user
const user = await User.create({
name: 'John Doe',
email: 'john@example.com'
});
// Soft delete (sets isDeleted: true, deletedAt: Date)
await user.remove();
// User is excluded from normal queries
const users = await User.find().all(); // Won't include deleted user
// Find including soft-deleted
const allUsers = await User.findWithDeleted().all();
// Find only soft-deleted
const deletedUsers = await User.findDeleted().all();
// Restore the user
await User.restore(user._id);
// User is now back in normal queries
const users = await User.find().all(); // Includes restored user
Benefits:
- Data recovery capabilities
- Audit trails
- Analytics on deleted data
- Compliance requirements
4. Automatic Partial Text Search
No regex needed for partial matching:
// Automatic partial text search
const users = await User.find({
nameContains: 'john', // Searches name field (case-insensitive)
emailContains: 'gmail' // Searches email field (case-insensitive)
}).all();
// Works with nested fields too
const posts = await Post.find({
'user.emailContains': 'gmail'
}).all();
The library automatically detects fields ending with "Contains" and generates case-insensitive LIKE queries.
5. Graph Database Support (OGM)
Work with graphs naturally using the Object Graph Mapper:
import { graphModel } from 'arango-typed';
// Create a graph model
const User = graphModel(db, 'social_graph', 'users', userSchema);
// Create relationships (edges)
await User.createRelationship('users/alice', 'users/bob', 'friends', {
since: new Date(),
strength: 0.9
});
// Traverse graph (BFS)
const friends = await User.traverse('users/alice', {
direction: 'outbound',
edgeCollection: 'friends',
maxDepth: 2,
strategy: 'bfs'
});
// Find shortest path
const path = await User.shortestPath('users/alice', 'users/charlie');
// Get all paths
const allPaths = await User.getAllPaths('users/alice', 'users/charlie', {
maxDepth: 3
});
// Count relationships
const friendCount = await User.countRelationships('users/alice', 'friends', 'outbound');
Graph Features:
- Relationship access like object properties
- BFS and DFS traversals
- Shortest path queries
- K-shortest paths
- Path existence checks
- Relationship counting
6. Enhanced Many-to-Many Relationships
Use native graph edges for many-to-many relationships:
import { BelongsToMany } from 'arango-typed';
// Define many-to-many using graph edges (recommended)
const userRolesRelation = new BelongsToMany(User, Role, {
through: 'user_roles', // Edge collection
useGraph: true, // Use graph edges
graphName: 'app_graph', // Graph name
direction: 'outbound' // Direction
});
// Get related documents
const roles = await userRolesRelation.getRelated(user);
// Associate documents
await userRolesRelation.associate(user, role);
// Disassociate
await userRolesRelation.disassociate(user, role);
7. Vector Search & LangChain Integration
Build RAG (Retrieval-Augmented Generation) applications easily:
import { ArangoRAG } from 'arango-typed/integrations/langchain';
// Create RAG instance
const rag = new ArangoRAG(db, {
collection: 'documents',
embeddingField: 'embedding',
textField: 'content'
});
// Add documents with embeddings
await rag.addDocuments([
{
pageContent: 'Hello world',
metadata: { source: 'doc1' },
embedding: [0.1, 0.2, 0.3, ...] // Your embedding vector
}
]);
// Retrieve context for LLM
const context = await rag.retrieve('What is hello?', {
topK: 5,
scoreThreshold: 0.7
});
// Use with LangChain
const retriever = rag.asRetriever();
const chain = RetrievalQAChain.fromLLM(llm, retriever);
const answer = await chain.call({ query: 'What is hello?' });
LangChain Features:
- VectorStore implementation
- RAG support
- MCP (Model Context Protocol) integration
- Hybrid search with reranking
- Multi-tenancy support
8. Query Builder
Chainable query builder with powerful operators:
// Complex queries
const users = await User.find({
age: { $gte: 18, $lte: 65 },
email: { $regex: /@gmail\.com$/ },
status: { $in: ['active', 'pending'] },
$or: [
{ role: 'admin' },
{ role: 'moderator' }
]
})
.sort({ createdAt: -1 })
.limit(10)
.skip(20)
.all();
// Lean queries (returns plain objects, faster)
const leanUsers = await User.findLean({ active: true }).all();
// Count
const count = await User.count({ active: true });
Real-World Use Cases
Multi-Tenant SaaS Applications
Perfect for building SaaS platforms with automatic tenant isolation:
// Automatic tenant filtering
const User = model('users', userSchema, {
tenantEnabled: true,
auditEnabled: true,
softDeleteEnabled: true
});
// All operations automatically respect tenant boundaries
app.get('/users', async (req, res) => {
const users = await User.find({}); // Only current tenant
res.json(users);
});
Social Networks & Recommendations
Leverage graph capabilities for social features:
// Friend recommendations
const recommendations = await User.traverse(currentUserId, {
direction: 'outbound',
edgeCollection: 'friends',
maxDepth: 2,
filter: { status: 'active' }
});
// Find mutual connections
const mutual = await User.findMutualConnections(user1Id, user2Id);
AI/ML Applications
Build RAG systems and semantic search:
// Semantic search
const results = await vectorSearch.similaritySearch(
'documents',
queryEmbedding,
{ topK: 10, scoreThreshold: 0.8 }
);
// Hybrid search (vector + keyword)
const hybridResults = await rag.hybridSearch(query, {
vectorWeight: 0.7,
keywordWeight: 0.3
});
Enterprise Applications
Complete audit trails and compliance:
// Track all changes
const User = model('users', userSchema, {
auditEnabled: true
});
// Get complete audit history
const auditLog = await User.getAuditLogs(userId);
// Returns: [{ action: 'create', userId: '...', timestamp: ..., changes: {...} }, ...]
Performance
arango-typed is optimized for performance:
- Query Caching - Compiled queries are cached for reuse
- Direct DB Access - Bypasses Document wrapper when hooks aren't needed
- Compiled Validators - Validators are compiled and cached
- Batch Operations - Efficient bulk inserts and updates
- Lean Queries - Return plain objects for better performance
Result: Only ~10-15% overhead compared to using the raw ArangoDB driver, while providing a much better developer experience.
Framework Support
arango-typed works with all major Node.js frameworks:
- ✅ Express.js - Full middleware support
- ✅ Fastify - Adapter available
- ✅ Koa - Adapter available
- ✅ NestJS - Adapter available
- ✅ Next.js - Full support
- ✅ Hono - Adapter available
Documentation
Comprehensive documentation is available with interactive examples:
📖 Full HTML Documentation - Beautiful, interactive documentation site
Key Documentation Pages
- Getting Started - Installation and basic setup
- Models & Schemas - Define and use data models
- Queries - Query builder and operators
- Multi-Tenancy - Automatic tenant filtering
- Audit Functionality - Change tracking
- Soft Delete - Soft delete with restore
- Relationships - HasOne, HasMany, BelongsTo, BelongsToMany
- Graph Database (OGM) - Object Graph Mapper
- LangChain Integration - RAG and VectorStore
- Performance - Optimization guide
- Express Integration - Express.js setup
Latest Updates
v1.6.0 (Latest)
New Features:
- ✨ Comprehensive audit functionality with automatic tracking
- 🔍 Automatic audit fields (createdBy, createdAt, updatedBy, updatedAt, deletedBy, deletedAt)
- 📊 Audit log retrieval methods (by document, user, or action)
- 🔗 Integration with multi-tenancy and soft delete
v1.5.0
New Features:
- 🗑️ Soft delete with restore capabilities
- 🔄 Automatic filtering of soft-deleted documents
- 📝 Enhanced documentation
v1.4.0
New Features:
- 🔍 Automatic partial text search (nameContains, emailContains, etc.)
- 📚 Comprehensive LangChain integration documentation
- 🎨 Enhanced documentation site
Installation & Links
Install from npm
npm install arango-typed arangojs
Links
- 📦 npm Package: https://www.npmjs.com/package/arango-typed
- 💻 GitHub Repository: https://github.com/muhammedshafeeque/arango-typed
- 📖 Documentation: https://muhammedshafeeque.github.io/arango-typed/
- 🐛 Issues: https://github.com/muhammedshafeeque/arango-typed/issues
- 💬 Discussions: https://github.com/muhammedshafeeque/arango-typed/discussions
Contributing
Contributions are welcome! Whether it's:
- 🐛 Bug reports
- 💡 Feature suggestions
- 📝 Documentation improvements
- 💻 Code contributions
Check out the Contributing Guide to get started.
Example: Complete Express.js Application
Here's a complete example of a multi-tenant SaaS application:
import express from 'express';
import { connect, Schema, model, tenantMiddleware, AuditContext } from 'arango-typed';
// Connect to database
await connect('http://localhost:8529/myapp', {
username: 'root',
password: ''
});
// Define schema
const userSchema = new Schema({
name: String,
email: { type: String, required: true, unique: true },
role: { type: String, enum: ['user', 'admin'], default: 'user' },
active: { type: Boolean, default: true }
});
// Create model with all features enabled
const User = model('users', userSchema, {
tenantEnabled: true,
auditEnabled: true,
softDeleteEnabled: true
});
// Express app
const app = express();
app.use(express.json());
// Middleware: Extract tenant and set audit context
app.use(tenantMiddleware({ extractFrom: 'header' }));
app.use((req, res, next) => {
const userId = req.headers['x-user-id'] as string;
if (userId) {
AuditContext.set(userId, {
ip: req.ip,
userAgent: req.get('user-agent')
});
}
next();
});
// Routes
app.get('/users', async (req, res) => {
// Automatically filtered by tenant
const users = await User.find({ active: true }).all();
res.json(users);
});
app.post('/users', async (req, res) => {
// Tenant and audit fields automatically added
const user = await User.create(req.body);
res.json(user);
});
app.put('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
// Audit fields automatically updated
await user.update(req.body);
res.json(user);
});
app.delete('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
// Soft delete (sets isDeleted: true)
await user.remove();
res.json({ success: true });
});
app.get('/users/:id/audit', async (req, res) => {
const logs = await User.getAuditLogs(req.params.id);
res.json(logs);
});
app.listen(3000);
Conclusion
arango-typed brings a Mongoose-like experience to ArangoDB with full TypeScript support, production-ready features, and excellent performance. Whether you're building:
- 🏢 Multi-tenant SaaS applications
- 🌐 Social networks with graph features
- 🤖 AI/ML applications with RAG
- 🏛️ Enterprise applications with audit requirements
arango-typed has you covered with features like multi-tenancy, audit tracking, soft delete, graph support, and vector search — all with a familiar API and full type safety.
Get started today:
npm install arango-typed arangojs
Give it a try and let me know what you think! ⭐
Tags: #typescript #arangodb #nodejs #orm #graphdatabase #opensource #webdev #programming #database #express #langchain #vectorsearch #multitenancy #audit #softdelete #typescript #mongodb #mongoose #backend #api
Top comments (0)