DEV Community

Cover image for Introducing Nitrite for Flutter : An embedded NoSQL database for Flutter
Anindya Chatterjee
Anindya Chatterjee

Posted on

Introducing Nitrite for Flutter : An embedded NoSQL database for Flutter

NOsql Object (NO2 a.k.a. Nitrite) is a server-less, embedded, and self-contained NoSQL database. It is an open-source project that provides a simple API for persistent data storage. Nitrite database is designed to be lightweight, fast, and easy to use. Apart from Flutter it is available in Java and Kotlin as well.

Nitrite database can be used in various scenarios where a lightweight, embedded, and server-less NoSQL database is required. Some of the use cases for Nitrite database are:

  • Mobile and desktop applications
  • IoT devices and sensors
  • Web applications and APIs
  • Prototyping and testing
  • Data caching and synchronization
  • Data analysis and reporting

Nitrite database is designed to be simple and easy to use, making it an ideal choice for Flutter applications. Nitrite is written in pure Dart without any native dependencies.

✨ Features

  • Embedded, server-less
  • Simple API
  • Document-oriented
  • Schema-less document collection and object repository
  • Extensible storage engines
  • Indexing and full-text search
  • Simple query API
  • In-memory and file-based store
  • Transaction support
  • Schema migration support
  • Encryption support

Nitrite also comes with a well written documentation with lots of examples to get you started.

πŸš€ Getting Started

Nitrite is a pure Dart database. It does not depend on any native library. So it can be used in any platform where Dart is supported. It is a server-less embedded database ideal for desktop, mobile, or web applications. It is written in pure Dart and runs in Flutter, Dart VM, and the browser. To use Nitrite in your project, add the following package to your package:

dart pub add nitrite
Enter fullscreen mode Exit fullscreen mode

By design, Nitrite is modular and extensible. It has a core module which provides all the basic features. Additional features like persistent storage, spatial indexing, encryption etc. are available as separate modules. You only need to add the modules you need.

As for example, if you want to use Nitrite with persistent storage, add the following additional dependency in your project:

dart pub add nitrite_hive_adapter
Enter fullscreen mode Exit fullscreen mode

More on the module API can be found here.

✍️ Usage

To create a new database or open an existing database, use the builder API to create a database instance:

import 'package:nitrite/nitrite.dart';

var db = await Nitrite.builder()
    .openOrCreate(username: 'user', password: 'pass123');
Enter fullscreen mode Exit fullscreen mode

By default, Nitrite uses in-memory storage. To use persistent storage, load a persistent storage module. Nitrite provides a persistent storage module based on Hive.

// create a hive backed storage module
var storeModule = HiveModule.withConfig()
    .crashRecovery(true)
    .path('$dbDir/db')
    .build();


// initialization using builder
var db = await Nitrite.builder()
    .loadModule(storeModule)
    .openOrCreate(username: 'user', password: 'pass123');
Enter fullscreen mode Exit fullscreen mode

πŸ—‚οΈ Nitrite Collection

Nitrite stores data as a collection of documents. A Document is a simple key-value pair. To store a document in a collection, use the following code:

var coll = await db.collection('test');

// create a document
var document = createDocument("firstName", "John")
    .put("phone", ["212-555-1234", "646-555-4567"]);

// insert the document
await coll.insert(document);
Enter fullscreen mode Exit fullscreen mode

More on the NitriteCollection is available here.

πŸ“¦ Object Repository

Nitrite also provides ObjectRepository which is nothing but a abstraction over NitriteCollection to store Dart objects. Nitrite uses converters to map a Dart object to a document and stores it in a collection.

var repo = await db.getRepository<Person>();

// create a person object
var person = Person()
    ..firstName = 'John'
    ..lastName = 'Doe'
    ..age = 30
    ..address = Address()
      ..street = '21 2nd Street'
      ..city = 'New York'
      ..state = 'NY'
      ..country = 'USA'
      ..zip = '10021';

// insert the person object
await repo.insert(person);
Enter fullscreen mode Exit fullscreen mode

You can either write your own converter or use the Nitrite’s code generator to generate the converter for you. To use the code generator, add the following dev dependencies in your project:

dart pub add nitrite_generator --dev
dart pub add build_runner --dev
Enter fullscreen mode Exit fullscreen mode

More on ObjectRepository can be found in guide here.

πŸ“‡ Indexing

Nitrite supports indexing on single or multiple fields to optimize the performance of a database by minimizing the number of disk accesses required when a query is processed. It supports following types of indexes:

  • Unique Index
  • Non-Unique Index
  • Full-text Index
  • Spatial Index via spatial module

You can even create your own custom index using the Module API. To create an index on a field,

// create a non-unique index on field 'firstName'
await coll.createIndex(['firstName'], indexOptions(IndexType.nonUnique));

// create a full-text index on field 'note'
await coll.createIndex(['note'], indexOptions(IndexType.fullText));

// create a unique index on field 'phone' and 'email'
await coll.createIndex(['phone', 'email']);
Enter fullscreen mode Exit fullscreen mode

πŸ” Query

Nitrite provides a fluent API for find operation. It also provides a simple query DSL based on Dart language features like extension methods and operator overloading.

// find all documents where firstName is 'John'
var cursor = coll.find(filter: where('firstName').eq('John'));

// find all documents where firstName is 'John' and age is greater than 25
var cursor = coll.find(filter: 'name'.eq('John') & 'age' > 18);
Enter fullscreen mode Exit fullscreen mode

Extensive details about all types of Filters and example can be found here in the guide.

🀝 Transaction

Nitrite has support for transaction on NitriteCollection and ObjectRepository. Transactions can be used as follows:

var session = db.createSession();

await session.executeTransaction((transaction) async {
  var collection = await transaction.getCollection("test");
  await collection.insert(doc1);
}, rollbackFor: [NitriteException]);
Enter fullscreen mode Exit fullscreen mode

More on transaction can be found here.

There are many more features available in Nitrite which cannot be covered in this short introduction. To learn more about Nitrite, please visit the documentation. The project is open source and available in GitHub. If you have any questions, please feel free to ask in GitHub Discussions.

Top comments (0)