camo: a class-based ODM that runs on NeDB or MongoDB
A class-based ES6 ODM for Mongo-like databases.
At a glance
- What is it?
- camo is an ES6 object document mapper that gives Mongo-like databases a traditional class interface, with schemas declared as member variables, a Document base class, promises on every call, and pluggable backends where NeDB stands in for a real MongoDB instance. It is MIT licensed and runs on Node 2 and later.
- Who is it for?
- Adopt camo if you want a traditional class and document interface over a Mongo-like store, or if you want to run the same code against NeDB in development and MongoDB in production without a real Mongo instance. Skip it if your project is already happy with a query-style client, since the class model is a deliberate preference rather than a necessity, and skip it if you need current MongoDB driver features.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An ODM written by someone who wanted classes
camo is a class-based ES6 ODM for Mongo-like databases, and the README is unusually honest about why it exists. The section headed why do we need another ODM opens with a short answer, we probably don't, and then gives two reasons: to bring traditional-style classes to MongoDB JavaScript, and to support NeDB as a backend, which it describes as much like the SQLite alternative to Mongo. The author then explains the motivation more personally, that throughout development the project turned into a library full of ES6 features, and that coming from a Java background it is easier to design and write code in terms of classes, and that this is probably true for many JavaScript beginners. The argument about ES6 classes is that they do not bring new functionality to the language, but they make it much easier to get into object-oriented programming in JavaScript, which is reason enough for a new library in the author's view. That origin story matters for evaluation, because a library written to serve one developer's background is also a library whose conventions will feel natural to people from that background and slightly off to everyone else. The primary language is JavaScript and the package is published as camo on npm.
Installing it means choosing one backend
The install section is short and has a required first step and a required choice. You must first have installed Node greater than 2.0.x, then run the install command for the library.
npm install camo --saveAnd at least one of the following backends.
npm install nedb --save npm install mongodb --saveThe package metadata backs this up, since the two backends are optional dependencies, mongodb at 2.0.42 and nedb at 1.8.0, while the required dependencies are just depd at 1.1.0 and lodash at 4.17.21. The engines field asks for Node 2.0.0 or newer and the test script is mocha, with chai 3.0.0 and mocha 2.2.5 as the dev dependencies. The versions involved are the giveaway about the age of the project, since those are the dependency lines of the early Node ecosystem rather than current ones, and the last push to the repository was on 2026-04-02 with the version at 0.12.5 and no GitHub releases. The NeDB route is the interesting one for a reader today, because NeDB is an embedded store, so a developer can build and test an application without installing a database server at all, and the README also notes that this lets you use Camo in the browser since NeDB supports in-memory storage.
Connecting, and the URI format is where the backend shows
Before using any document methods you must connect to the underlying database, and each supported database has its own unique URI string describing the network or file location. The README gives the format and an example for each. For MongoDB the format is mongodb://[username:password@]host[:port][/db-name] with an example of a URI with credentials pointing at a local server. For NeDB the format is nedb://[directory-path] OR nedb://memory, with an example pointing at a directory path, and the memory form is what lets the library work without a database on disk. The connect call is promise based, so the database arrives asynchronously and is assigned when it resolves.
var connect = require('camo').connect;
var database;
var uri = 'nedb:///Users/scott/data/animals';
connect(uri).then(function(db) {
database = db;
});The alternative to the URI form is that each backend takes a different set of connection details, and a URI string is the layer that hides that difference, which is the main reason the library can sit over two quite different databases. The README notes that some databases support more than just network or file locations, and NeDB is the example given, since it can store data in memory.
A document is a class with member variables as the schema
All models must inherit from the Document class, which handles much of the interface to the backend NoSQL database, and the schema is declared in the constructor as member variables. The example is a Company class with a name, a valuation object carrying a type, a default and a minimum, an array of employee strings, and a date founded with a default of Date.now.
var Document = require('camo').Document;
class Company extends Document {
constructor() {
super();
this.name = String;
this.valuation = {
type: Number,
default: 10000000000,
min: 0
};
this.employees = [String];
this.dateFounded = {
type: Date,
default: Date.now
};
}
static collectionName() {
return 'companies';
}
}Two rules follow from that. All public member variables are added to the schema, and a field is kept out of it by prefixing its name with a single low line character, which gives you a convention for keeping a field out of the stored document. And the collection name is set by overriding the static collectionName method, which should return the desired name as a string, and if one is not given then Camo uses the name of the class and naively appends an s to the end to make it plural. That fallback is the kind of detail that surprises people, since a class named Person becomes a persons collection, so a document that is not meant to be plural needs an explicit collectionName. Schemas can also be declared with a this.schema method, which takes the same options object, so the two styles are equivalent and the difference is only how the declaration reads next to the constructor.
Types, typed arrays and what gets validated when
The supported variable types are listed explicitly, and the list is what a schema can hold: String, Number, Boolean, Buffer, Date, Object, Array, EmbeddedDocument and Document Reference. The array handling is the part with real behaviour attached. Arrays can be declared as either un-typed, using Array or an empty pair of brackets, or typed with the [TYPE] syntax such as [String], and typed arrays are enforced by Camo on save, with an Error thrown if a value of the wrong type is saved in the array. Arrays of references are also supported, and the separate EmbeddedDocument type is what the embedded documents feature of the quick start is about. The type declarations themselves use the same options object as the schema method, with a type, a default and constraints such as a minimum, which is what the example shows for the valuation field. What this means in practice is that a good part of the schema is enforced at save time rather than at read time, which is the opposite of how a plain MongoDB driver behaves, and it is the main reason to use an ODM at all.
Where camo is the wrong choice
The first limit is the ecosystem, and it is the reason most teams would not reach for this library. The optional MongoDB driver is pinned at 2.0.42, which is a major version from years ago, so the library talks to MongoDB through an old driver, and any behaviour of a current server that the old driver does not understand is out of reach. The same applies to Node itself, since the engines field asks for Node 2.0.0 or newer, which is a floor rather than a ceiling but reflects a codebase written for that era. The second is the promise the README itself makes against, that we probably do not need another ODM, and it is fair. If a team is comfortable with a query-style client, an ODM adds a layer of conventions, a schema declaration style and a validation pass without changing what the database can do. The third is the collection naming fallback, where a class name becomes a plural by appending an s, which is a small thing that produces wrong collection names in a hurry, and the same naivety appears elsewhere in the design, since the author describes it as naive. The fourth is the schema as constructor member variables, which is unconventional next to the schema method that does the same job, and a codebase that uses both will read as though there are two ways to do one thing. And the fifth is that the ODM pattern itself has fallen out of fashion in the JavaScript ecosystem, so a new project written today would more likely reach for a typed query builder and get validation from a schema library alongside it rather than from the data layer.
Editorial conclusion
Adopt camo if you want a traditional class and document interface over a Mongo-like store, or if you want to run the same code against NeDB in development and MongoDB in production without a real Mongo instance. Skip it if your project is already happy with a query-style client, since the class model is a deliberate preference rather than a necessity, and skip it if you need current MongoDB driver features. Verify first which backend you are on, since the optional dependencies pin specific versions, that your Node version is supported, and that the schema validation rules for typed arrays match the data you plan to save.
Frequently asked questions
What is camo and which databases does it support?
Camo is a class-based ES6 object document mapper for Mongo-like databases, created to bring traditional-style classes to MongoDB JavaScript and to support NeDB as a backend, which is much like the SQLite alternative to Mongo. Backends are installed as optional dependencies, nedb at 1.8.0 and mongodb at 2.0.42, and the library itself needs only depd and lodash.
How do I declare a document schema and its collection in camo?
Your model inherits from the Document class and declares the schema as public member variables in the constructor, or through the this.schema method. The collection name comes from overriding the static collectionName method; if you do not, Camo uses the class name and naively appends an s to make it plural.
Which field types does camo support and when are they validated?
The supported types are String, Number, Boolean, Buffer, Date, Object, Array, EmbeddedDocument and Document Reference. Arrays can be un-typed or typed with the [TYPE] syntax, and typed arrays are enforced on save, with an Error thrown if a value of the wrong type is saved in the array. Arrays of references are also supported.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/scottwrobinson-camo)Was this useful?