nitrite-java is a free, open source data warehousing & processing project written in Java and released under Apache-2.0. It has 916 GitHub stars, 95 forks and 0 open issues, and was last pushed 4 days ago. On this registry it ranks #17 of 19 tracked projects in Data Warehousing & Processing, with 5 head-to-head comparisons available.

What is nitrite-java?

Nitrite (NOsql Object, or NO2) is an open-source, Apache-2.0 licensed NoSQL embedded document store for Java that runs inside the application process and is aimed at developers building desktop, mobile, and small web applications.

What it is

Nitrite is a Java library that provides a document-oriented database running embedded in the same process as the application, with no separate server to start or connect to. It stores data either entirely in memory or in file-based persistent storage, and it supports both schemaless document collections and typed object repositories. Data can be modelled as free-form Document objects or as annotated POJOs such as the Employee example, which carries Entity, Id, and Index annotations. Storage is pluggable: the README shows an MVStoreModule and a RocksDBModule as interchangeable storage engines, with mapper modules such as JacksonMapperModule loaded alongside them. The library is published to Maven Central under the org.dizitart group, and its topics place it in the embedded-database and object-database space. Sibling projects exist within the same ecosystem: Potassium Nitrite, a Kotlin extension, and nitrite-flutter, a Flutter/Dart version.

The concrete problem it solves is the operational overhead of running a document database as a separate service when an application does not need one. A desktop application, an Android app, or a small web application would otherwise have to provision, deploy, and connect to a database server. Nitrite removes that tier entirely: the database becomes a dependency in the build file, opened through Nitrite.builder() and openOrCreate with a user name and password, and it keeps working in environments where a server cannot run at all. Because the same API covers in-memory and file-based storage, the in-memory mode is usable for tests and ephemeral data while the file mode persists to a path such as /tmp/test.db.

Key capabilities

  • Embedded, serverless deployment, with no separate database server process to install or manage.
  • Pluggable storage engines, including MVStoreModule with optional compression via compress(true) and RocksDBModule configured through withConfig().filePath(...).
  • Two data models in one library: schemaless NitriteCollection documents and typed ObjectRepository instances built from annotated POJOs.
  • Indexing and full-text search, declared with the Index annotation and index types such as IndexType.NON_UNIQUE and IndexType.FULL_TEXT.
  • Transaction support and schema migration support for data that evolves over releases.
  • Encryption support, with databases and repositories opened under a user name and password.
  • Android compatibility at API Level 26, plus a Kotlin extension called Potassium Nitrite and a Flutter/Dart counterpart called nitrite-flutter.

Who uses it and how

  • Desktop and mobile application developers who need local persistence without shipping a database server alongside the app.
  • Android developers, for whom the nitrite-android-demo Todo application demonstrates usage on API Level 26 and above.
  • Small web applications that need document storage and object mapping within a single process.
  • Kotlin teams working through the Potassium Nitrite extension, and Dart or Flutter teams working through nitrite-flutter.
  • Java teams that want an in-memory mode for tests and a file-backed mode for production data behind one API.

Getting started

Add the nitrite-bom bill of materials from the org.dizitart group, then add the nitrite artifact plus a storage adapter such as nitrite-mvstore-adapter, using either Maven or Gradle. The README warns that version 4.x contains breaking API changes, so the linked guide should be read before upgrading from 3.x.

How it compares

The facts provided do not name any other tool as a comparable alternative, so Nitrite stands alone in this registry entry. The only related projects named are its own ecosystem members, the Potassium Nitrite Kotlin extension and the nitrite-flutter port.

When to use it — and when not

Nitrite fits when the application itself should own its data, such as a desktop tool, an Android app, or a small web service, and the deployment must not include a database server. It is a weaker fit for teams that need an administrative console or a synchronisation service, because the README marks Nitrite DataGate and Nitrite Explorer as deprecated and no longer maintained. Teams upgrading from version 3.x must also budget for the breaking API changes in 4.x and consult the separate online guide, since the README itself is largely installation instructions and code examples.

project readme (upstream, from github) — read inline

Nitrite Database

Build CodeQL codecov javadoc Discussion

NOsql Object (NO2 a.k.a Nitrite) database is an open source nosql embedded document store. It supports both in-memory and file based persistent store.

Nitrite is an embedded database ideal for desktop, mobile or small web applications.

It features:

  • Embedded, serverless
  • Simple API
  • Document-oriented
  • Schemaless document collection and object repository
  • Extensible storage engines - mvstore, rocksdb
  • Indexing and full-text search
  • Simple query api
  • In-memory and file-based store
  • Transaction support
  • Schema migration support
  • Encryption support
  • Android compatibility (API Level 26)

Kotlin Extension

Nitrite has a kotlin extension called Potassium Nitrite for kotlin developers. Visit here for more details.

Flutter Version

If you are looking for Nitrite for Flutter/Dart, head over to nitrite-flutter.

Deprecation Notice

Nitrite DataGate and Nitrite Explorer is now deprecated and no longer maintained.

Getting Started with Nitrite

NOTE: There are breaking api changes in version 4.x. So please read the guide before upgrading from 3.x.x.

How To Install

To use Nitrite in any Java application, first add the nitrite bill of materials, then add required dependencies:

Maven

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.dizitart</groupId>
            <artifactId>nitrite-bom</artifactId>
            <version>[latest version]</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.dizitart</groupId>
        <artifactId>nitrite</artifactId>
    </dependency>

    <dependency>
        <groupId>org.dizitart</groupId>
        <artifactId>nitrite-mvstore-adapter</artifactId>
    </dependency>
</dependencies>

Gradle


implementation(platform("org.dizitart:nitrite-bom:[latest version]"))
    
implementation 'org.dizitart:nitrite'
implementation 'org.dizitart:nitrite-mvstore-adapter'

Examples

A Todo android application is available here to demonstrate the usage of Nitrite in android.

Quick Examples

Initialize Database

// create a mvstore backed storage module
MVStoreModule storeModule = MVStoreModule.withConfig()
    .filePath("/tmp/test.db") 
    .compress(true)
    .build();

// or a rocksdb based storage module
RocksDBModule storeModule = RocksDBModule.withConfig()
    .filePath("/tmp/test.db")
    .build();


// initialization using builder
Nitrite db = Nitrite.builder()
        .loadModule(storeModule)
        .loadModule(new JacksonMapperModule())  // optional
        .openOrCreate("user", "password");

Create a Collection

// Create a Nitrite Collection
NitriteCollection collection = db.getCollection("test");

// Create an Object Repository
ObjectRepository<Employee> repository = db.getRepository(Employee.class);

Annotations for POJO


@Entity(value = "retired-employee",     // entity name (optional), 
    indices = {
        @Index(value = "firstName", type = IndexType.NON_UNIQUE),
        @Index(value = "lastName", type = IndexType.NON_UNIQUE),
        @Index(value = "note", type = IndexType.FULL_TEXT),
})
public class Employee implements Serializable {
    // provides id field to uniquely identify an object inside an ObjectRepository
    @Id
    private long empId;
    private Date joinDate;
    private String firstName;
    private String lastName;
    private String note;

    // ... public getters and setters
}

CRUD Operations


// create a document to populate data
Document doc = Document.createDocument("firstName", "John")
     .put("lastName", "Doe")
     .put("birthDay", new Date())
     .put("data", new byte[] {1, 2, 3})
     .put("fruits", new ArrayList<String>() {{ add("apple"); add("orange"); add("banana"); }})
     .put("note", "a quick brown fox jump over the lazy dog");

// insert the document
collection.insert(doc);

// find a document
collection.find(where("firstName").eq("John").and(where("lastName").eq("Doe"));

// update the document
collection.update(where("firstName").eq("John"), createDocument("lastName", "Wick"));

// remove the document
collection.remove(doc);

// insert an object in repository
Employee emp = new Employee();
emp.setEmpId(124589);
emp.setFirstName("John");
emp.setLastName("Doe");

repository.insert(emp);

Create Indices


// create document index
collection.createIndex(indexOptions(IndexType.NON_UNIQUE), "firstName", "lastName"); // compound index
collection.createIndex(indexOptions(IndexType.FULL_TEXT), "note"); // full-text index

// create object index. It can also be provided via annotation
repository.createIndex(indexOptions(IndexType.NON_UNIQUE), "firstName");

Query a Collection


DocumentCursor cursor = collection.find(
    where("firstName").eq("John")               // firstName == John
    .and(
        where("data").elemMatch("$".lt(4))      // AND elements of data array is less than 4
            .and(
                where("note").text("quick")     // AND note field contains string 'quick' using full-text index
        )       
    )
);

for (Document document : cursor) {
    // process the document
}

// get document by id
Document document = collection.getById(nitriteId);

// query an object repository and create the first result
Cursor<Employee> cursor = repository.find(where("firstName").eq("John"));
Employee employee = cursor.firstOrNull();

Transaction

try (Session session = db.createSession()) {
    try (Transaction transaction = session.beginTransaction()) {
        NitriteCollection txCol = transaction.getCollection("test");

        Document document = createDocument("firstName", "John");
        txCol.insert(document);

        transaction.commit();
    } catch (TransactionException e) {
        transaction.rollback();
    }
}

Schema Migration


Migration migration1 = new Migration(Constants.INITIAL_SCHEMA_VERSION, 2) {
    @Override
    public void migrate(InstructionSet instructions) {
        instructions.forDatabase()
            // make a non-secure db to secure db
            .addUser("test-user", "test-password");

        // create instructions for existing repository
        instructions.forRepository(OldClass.class, "demo1")

            // rename the repository (in case of entity name changes)
            .renameRepository("migrated", null)

            // change datatype of field empId from String to Long and convert the values
            .changeDataType("empId", (TypeConverter<String, Long>) Long::parseLong)

            // change id field from uuid to empId
            .changeIdField(Fields.withNames("uuid"), Fields.withNames("empId"))

            // delete uuid field
            .deleteField("uuid")
    
            // rename field from lastName to familyName
            .renameField("lastName", "familyName")

            // add new field fullName and add default value as - firstName + " " + lastName
            .addField("fullName", document -> document.get("firstName", String.class) + " "
                + document.get("familyName", String.class))

            // drop index on firstName
            .dropIndex("firstName")

            // drop index on embedded field literature.text
            .dropIndex("literature.text")

            // change data type of embedded field from float to integer and convert the values 
            .changeDataType("literature.ratings", (TypeConverter<Float, Integer>) Math::round);
    }
};

Migration migration2 = new Migration(2, 3) {
    @Override
    public void migrate(InstructionSet instructions) {
        instructions.forCollection("test")
            .addField("fullName", "Dummy Name");
    }
};

MVStoreModule storeModule = MVStoreModule.withConfig()
    .filePath("/temp/employee.db")
    .compressHigh(true)
    .build();

db = Nitrite.builder()
    .loadModule(storeModule)
    
    // schema versioning is must for migration
    .schemaVersion(2)

    // add defined migration paths
    .addMigrations(migration1, migration2)
    .openOrCreate();

Import/Export Data

// Export data to json file

// create export options
ExportOptions exportOptions = new ExportOptions();
// set the nitrite factory
exportOptions.setNitriteFactory(() -> openDb("test.db"));
// set the collections to export
exportOptions.setCollections(List.of("first"));
// set the repositories to export
exportOptions.setRepositories(List.of("org.dizitart.no2.support.data.Employee", "org.dizitart.no2.support.data.Company"));
// set the keyed repositories to export
exportOptions.setKeyedRepositories(Map.of("key", Set.of("org.dizitart.no2.support.data.Employee")));
// create an exporter with export options
Exporter exporter = Exporter.withOptions(exportOptions);
exporter.exportTo("test.json");

// Import data from the file

// create import options
ImportOptions importOptions = new ImportOptions();
// set the nitrite factory
importOptions.setNitriteFactory(() -> openDb("new-test.db"));
// create an importer with import options
Importer importer = Importer.withOptions(importOptions);
importer.importFrom("test.json");

More details are available in the guide.

Release Notes

Release notes are available here.

Documentation

Reference API

Document

JavaDoc

Build

To build and test Nitrite, ensure you have JDK 11 (or higher) and Maven 3 installed.


git clone https://github.com/nitrite/nitrite-java.git
cd nitrite-java
mvn clean install

Support / Feedback

For issues with, questions about, or feedback create a discussion.

Bugs / Feature Requests

Think you’ve found a bug? Want to see a new feature in the Nitrite? Please open an issue here. But before you file an issue please check if it is already existing or not.

Maintainers

  • Anindya Chatterjee

Contributors

This project exists thanks to all the people who contribute. For more details please visit CONTRIBUTING.md.

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. Become a sponsor for this project.

Presentation & Talks

Idan Sheinberg has given a talk on Nitrite at Kotlin Everywhere - TLV Edition meetup on October 27, 2019. Please find his presentation here.

Special Thanks

JProfiler YourKit MacStadium

Frequently asked questions

Is nitrite-java free to use?

nitrite-java is open source under the Apache-2.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does nitrite-java do?

NoSQL embedded document store for Java

What is nitrite-java written in?

nitrite-java is primarily written in Java. Its source is publicly available at https://github.com/nitrite/nitrite-java, and it has 916 GitHub stars.