Cosmox is the missing ORM layer for CosmosDB — Type-safe, developer-friendly, designed to simplify data access and boost performance for TypeScript developers.
Have you been searching for a Prisma-style ORM for CosmosDB?
Are you still writing raw SQL for querying your CosmosDB?
Are you still writing hard-coded API endpoints to apply filtering on your data?
Are you still wrestling in a world without a proper, type-safe ORM for CosmosDB in Node.js?
If you answered "yes" to any of the questions above, you've come to the right place!
Cosmox is built for developers building data-driven applications on Azure CosmosDB NoSQL, offering a modern, type-safe abstraction over the @azure/cosmos
SDK — without sacrificing performance.
If you're tired of writing raw SQL queries with complex filters or managing inconsistent JSON responses, Cosmox is your new best friend.
Cosmox is not a replacement for @azure/cosmos — It's a lightweight abstraction built to make CosmosDB more accessible and type-safe for TypeScript developers.
The code above gives you query auto-completion based on the data model you specified for each container in Azure CosmosDB
- Data analytics dashboards
- E-commerce applications
- IoT telemetry processing
- Multi-tenant SaaS applications
- Internal admin panels
Features | cosmox |
@azure/cosmos |
---|---|---|
CRUD | ✅ Simplified, Type-safe API | ✅ Flexible, low-level API |
Type-safe filtering queries | ✅ Built-in, inspired by Prisma | SQL-based filtering |
Type-safe field selection | ✅ Automatic inference | Custom SQL required |
SQL query builder | ✅ Built-in and type-checked | Manual SQL writing |
Optimized SQL query generation | ✅ Automatic & performant | Developer-defined SQL |
Pagination | ✅ Built-in by default | Custom logic needed |
Input-validations | ✅ Automatic input validation | Limited built-in validation |
Developer experience | ✅ Prisma-like, fluent API | Low-level, more flexible |
Error messages | ✅ Actionable, contextual | Partial error messages |
Bbundle size | ✅ Small and focused | Larger due to broader feature set |
Install this package
npm install cosmox
yarn install cosmox
pnpm install cosmox
Define pure TypeScript as models for your containers
type User = {
id: string;
firstName: string;
lastName: string;
age: number;
createdAt: Date;
isSuperAdmin: boolean;
};
type Post = {
id: string;
title: string;
content: string;
createdBy: string; // foreign key - User.id
};
Instantiate the client
import { createClient } from 'cosmox';
// Example 1 - Using connection string
const orm = createClient({
database: '<DATABASE_ID>',
connectionString: '<DB_CONNECTION_STRING>',
models: (t) => ({
// infer your types as the models for your containers during initialization
user: t.createModel<User>({ container: '<USER_CONTAINER_ID>' }),
post: t.createModel<Post>({ container: '<POST_CONTAINER_ID>' }),
}),
});
// Example 2 - Using CosmosDB client options
const orm = createClient({
database: '<DATABASE_ID>',
// same type-definition as "CosmosClientOptions" from "@azure/cosmos"
cosmosClientOptions: {
endpoint: '<EXAMPLE_ENDPOINT>',
},
models: (t) => ({
user: t.createModel<User>({ container: '<USER_CONTAINER_ID>' }),
post: t.createModel<Post>({ container: '<POST_CONTAINER_ID>' }),
}),
});
✨ Done! You can now start to query CosmosDB using the ORM.
Make queries with simple filters
const getFilteredUsers = async () => {
return await orm.user.findMany({
where: { firstName: { contains: 'Sam' } },
});
};
const getFilteredUsers = async () => {
return await orm.user.findMany({
where: { age: { gte: 18 } },
});
};
const getFilteredUsers = async () => {
return await orm.user.findMany({
where: { createdAt: { gte: new Date('2024-01-01') } },
});
};
const getFilteredposts = async () => {
return await orm.post.findMany({
where: { createdBy: { equals: '<SOME_USER_ID>' } },
});
};
Make a query without any filters
// This will return maximum of 100 items by default
const result = orm.user.findMany({});
Or, make a query by applying some complex filters, field-selections, and pagination logic:
const getFilteredUsers = async () => {
return await orm.user.findMany({
where: {
firstName: {
startsWith: 'Sa',
endsWith: 'lyn',
mode: 'INSENSITIVE',
},
age: {
lte: 20,
gte: 10,
not: 15,
},
isSuperAdmin: {
not: true,
},
createdAt: {
lte: new Date('2024-12-31'),
gte: new Date('2024-12-01'),
not: new Date('2024-12-15'),
},
},
orderBy: {
firstName: 'ASC',
},
take: 10,
select: {
id: true,
firstName: true,
age: true,
},
nextCursor: '<PAGINATION_TOKEN>',
});
};
Find an item by ID
// without field-selection
const result = orm.user.findOne({
where: { id: 'USER_ID' },
});
// with field-selection
const result = orm.user.findOne<User>({
where: { id: 'USER_ID' },
select: { id: true, firstName: true },
});
Create an item
type CreateUserInput = Partial<User>;
const result = orm.user.create<CreateUserInput>({
data: {
firstName: '<FIRST_NAME>',
lastName: '<LAST_NAME>',
},
});
Update an item
type UpdateUserInput = Partial<User>;
const result = orm.user.update<UpdateUserInput>({
where: { id: '<USER_ID>' },
data: {
firstName: '<UPDATED_FIRST_NAME>',
},
});
Delete an item
const result = orm.user.delete({
where: { id: '<USER_ID>' },
});
Core Query builder- Audit fields configuration (system fields) such as
createdAt
,updatedAt
,archivedAt
, etc - Bulk create / update operations
- Observability - query logging
- Filtering on more complex data types such as: composite types, enums, enum arrays, string arrays & number arrays
We're building Cosmox to make CosmosDB more accessible for TypeScript developers, and we welcome contributions passionate about improving the developer experience — whether you're a CosmosDB user, a TypeScript enthusiast, a Prisma user, or part of the broader database community.
This project is not an official Azure nor Prisma product. Provided "as is" without warranty.