Getting started
Discover ObjectBox: The Lightning-Fast Mobile Database for Persistent Object Storage. Streamline Your Workflow, Eliminate Repetitive Tasks, and Enjoy a User-Friendly Data Interface.
Add ObjectBox to your project
Prefer to look at example code? Check out our examples repository.
To add ObjectBox to your Android project, follow the instructions in the objectbox-java README.
Once completed, continue with the next step of defining entity classes below.
Prefer to look at example code? Check out our examples repository.
The ObjectBox Java SDK and runtime libraries support applications:
running on the JVM on Linux (x86_64, arm64, armv7), Windows (x86_64) and macOS 10.15 or newer (x86_64, Apple M1)
written in Java or Kotlin
targeting at least Java 8
built with Gradle or Maven
ObjectBox tools and dependencies are available on the Maven Central repository.
Maven projects
To set up a Maven project, see the README of the Java Maven example project.
Gradle projects
The instructions assume a multi-project build is used.
Open the Gradle build script of your root project and
add a global variable to store the common version of ObjectBox dependencies and
add the ObjectBox Gradle plugin:
Open the Gradle build file for your application subproject and, after other plugins, apply the
io.objectboxplugin:
Using your IDE of choice with a Gradle project might require additional configuration. E.g.
For IntelliJ IDEA see the help page for Gradle.
For Eclipse see the Buildship project and Getting Started article.
Optionally, add a runtime library for each platform that your application should run on and instead apply the Gradle plugin after the dependencies block:
The ObjectBox database runs mostly in native code written in C/C++ for optimal performance. Thus, ObjectBox will load a runtime library: a “.dll” on Windows, a “.so” on Linux, and a “.dylib” on macOS.\
By default, the Gradle plugin adds a runtime library (only) for your current operating system. It also adds the Java SDK (objectbox-java) and if needed the ObjectBox Kotlin extension functions (objectbox-kotlin).
ObjectBox only supports 64-bit systems for best performance going forward. Talk to us if you require 32-bit support.
Your project can now use ObjectBox, continue by defining entity classes.
You can watch these video tutorials as well 😀:
Prefer to look at example code? Check out our examples directory.
To add ObjectBox to your Flutter project:
Run these commands:
Or to use ObjectBox Sync (requires access to the Sync feature) instead run:
To run unit tests on your machine, download the latest native ObjectBox library for your machine by running this script in a bash shell (e.g. Git Bash on Windows):
bash <(curl -s https://raw.githubusercontent.com/objectbox/objectbox-dart/main/install.sh)
To get a variant of the library that supports ObjectBox Sync, append the --sync argument to above command.
This should add lines like this to your
pubspec.yaml:
If you added the above lines manually, then install the packages with
flutter pub get.
For all iOS apps target iOS 15.0: in ios/Podfile change the platform and in the ios/Runner.xcodeproj/poject.pbxproj file update IPHONEOS_DEPLOYMENT_TARGET (or open the Runner workspace in Xcode and edit the build setting). In ios/Flutter/AppframeworkInfo.plist update MinimumOSVersion to 15.0.
For all macOS apps target macOS 11.0: in macos/Podfile change the platform and in the macos/Runner.xcodeproj/poject.pbxproj file update MACOSX_DEPLOYMENT_TARGET (or open the Runner workspace in Xcode and edit the build setting).
For macOS apps using Sync, open macos/Runner.xcodeproj in Xcode and for the Runner target under Signing & Capabilities in the App Sandbox sections, enable incoming and outgoing network access.
For Linux Desktop apps: the Flutter snap ships with an outdated version of CMake. Install Flutter manually instead to use the version of CMake installed on your system.
Prefer to look at example code? Check out our examples directory.
Run these commands:
This should add lines like this to your
pubspec.yaml:
If you added the above lines manually, then install the packages with
dart pub getInstall the ObjectBox C library for your system (on Windows you can use "Git Bash"):
Or to use ObjectBox Sync (requires access to the Sync feature) instead run:
By default the library is downloaded into the lib subdirectory of the working directory. It's not necessary to install the library system-wide. This also allows to use different versions for different projects. For details see below.
Deploying Dart Native projects
Natively compiled Dart applications that use ObjectBox Dart require a reference to the objectbox-c library. Hence, the shared library file downloaded with install.sh needs to be shipped with the executable.
The install.sh script downloads the library by default to the lib subdirectory of the working directory. An executable using ObjectBox Dart looks for the library in this lib directory.
If it is not found there, it falls back to using system directories (using Dart's DynamicLibrary.open):
Windows: working directory and
%WINDIR%\system32.macOS:
/usr/local/lib(and maybe others).Linux:
/liband/usr/lib(again, possibly others).
Prefer to look at example code? Check out our examples directory.
ObjectBox for Python is available via PyPI: Stable Version (4.0.0):
If you encounter any problems in this or later steps, also check the FAQ and Troubleshooting pages.
Define Entity Classes
Define your data model by creating a class with at least an ID property, a so called entity.
A simple entity representing a user with an ID and a name property could look like this:
When using a data class, add default values for all parameters. This will ensure your data class will have a constructor that can be called by ObjectBox. (Technically this is only required if adding properties to the class body, like custom or transient properties or relations, but it's a good idea to do it always.)
Avoid naming properties like reserved Java keywords, like private and default. ObjectBox tooling works with the Java representation of your Kotlin code to be compatible with both Java and Kotlin. It will ignore such properties.
You can have multiple entities in the same file (here models.dart), or you can have them spread across multiple files in your package's lib directory.
Important:
Entities must have exactly one 64-bit integer ID property (a Java
long, KotlinLong, Dartint). If you need another type for the ID, like a string, see the @Id annotation docs for some tips. Also, the ID property must have non-private visibility (or non-private getter and setter methods).Entities must also have a no-argument constructor, or for better performance, a constructor with all properties as arguments. In the above examples, a default, no-argument constructor is generated by the compiler.
Support for many property types is already built-in, but almost any type can be stored with a converter.
For more details about entities, like how to create an index or a relation, check the Entity Annotations page.
You can also learn more about the ObjectBox model.
ObjectBox also supports changing your model at a later point. You can add and remove properties in entities and the database model is updated automatically (after re-generating some code, see section below). There is no need to write migration code.
To rename entities or properties, change the type of a property and more details in general see Data Model Updates.
Generate ObjectBox code
Next, we generate some binding code based on the model defined in the previous step.
Build your project to generate the MyObjectBox class and other classes required to use ObjectBox, for example using Build > Make Project in Android Studio.
Note: If you make significant changes to your entities, e.g. by moving them or modifying annotations, make sure to rebuild the project so generated ObjectBox code is updated.
To change the package of the MyObjectBox class, see the annotation processor options on the Advanced Setup page.
To generate the binding code required to use ObjectBox run
dart run build_runner build
ObjectBox generator will look for all @Entity annotations in your lib folder and create
a single database definition
lib/objectbox-model.jsonandsupporting code in
lib/objectbox.g.dart.
To customize the directory where generated files are written see Advanced Setup.
If you make changes to your entities, e.g. by adding a property or modifying annotations, or after the ObjectBox library has updated make sure to re-run the generator so generated ObjectBox code is updated.
You typically commit the generated code file objectbox.g.dart to your version control system (e.g. git) to avoid having to re-run the generator unless there are changes.
Actually we lied above. The generator will process lib and test folders separately and generate files for each one (if @Entity classes exist there). This allows to create a separate test database that does not share any of the entity classes with the main database.
Python bindings offer a convenient default Model to which Entity definitions are automatically associated if not specified otherwise. Similar to the other bindings, a JSON model file is also used for management of Schema history (i.e. to handle add/remove/rename of Entity and Property).
Among other files ObjectBox generates a JSON model file, by default to
app/objectbox-models/default.jsonfor Android projects,lib/objectbox-model.jsonfor Dart/Flutter projects, or<user-module-dir>/objectbox-model.jsonfor Python projects
To change the model file path, see Advanced Setup.
In Android Studio you might have to switch the Project view from Android to Project to see the default.json model file.
Python checks for the call-stack to determine the user-module directory in which the JSON file is stored.
This JSON file changes when you change your entity classes (or sometimes with a new version of ObjectBox).
Keep this JSON file, commit the changes to version control!
This file keeps track of unique IDs assigned to your entities and properties. This ensures that an older version of your database can be smoothly upgraded if your entities or properties change.
The model file also enables you to keep data when renaming entities or properties or to resolve conflicts when two of your developers make changes at the same time.
Create a Store
BoxStore (Java) or Store (Dart) is the entry point for using ObjectBox. It is the direct interface to the database and manages Boxes. Typically, you want to only have a single Store (single database) and keep it open while your app is running, not closing it explicitly.
Create it using the builder returned by the generated MyObjectBox class, for example in a small helper class like this:
If you encounter UnsatisfiedLinkError or LinkageError on the build call, see App Bundle, split APKs and Multidex for solutions.
The best time to initialize ObjectBox is when your app starts. We suggest to do it in the onCreate method of your Application class:
Create it using the builder returned by the generated MyObjectBox class, for example in a small helper class like this:
If you encounter UnsatisfiedLinkError or LinkageError on the build call, see App Bundle, split APKs and Multidex for solutions.
The best time to initialize ObjectBox is when your app starts. We suggest to do it in the onCreate method of your Application class:
The best time to initialize ObjectBox is when your app starts. For a command line app this is typically inside the main method.
Create it using the generated openStore() method, for example in a small helper class like this:
For sandboxed macOS apps also pass macosApplicationGroup to openStore(). See the notes about "macOS application group" in the constructor documentation of the Store class.
For example:
openStore(macosApplicationGroup: "FGDTDLOBXDJ.demo")
On mobile devices or sandboxed apps data should be stored in the app's documents directory. See Flutter: read & write files for more info. This is exactly what openStore()does, if the directory argument is not specified.
On desktop systems it is recommended to specify a directory to create a custom sub-directory to avoid conflicts with other apps.
If your code passes a directory that the application can't write to, you get an error that looks somewhat like this: failed to create store: 10199 Dir does not exist: objectbox (30).
The best time to initialize ObjectBox is when your app starts. We suggest to do it in your app's main() function:
When using Dart isolates, note that each Dart isolate has its own global fields, they do not share state on the Dart level.
However, as ObjectBox runs on the native or process level (so one native instance shared across all isolates), instead of creating a new Store in another isolate your code should instead attach to the open native store.
Create it using the generated openStore() method, for example like this:
The above minimal example omits the argument to (directory: ), using the default - ./objectbox - in the current working directory.
When using Dart isolates, note that each Dart isolate has its own global fields, they do not share state on the Dart level.
However, as ObjectBox runs on the native or process level (so one native instance shared across all isolates), instead of creating a new Store in another isolate your code should instead attach to the open native store.
It is possible to specify various options when building a store. Notably for testing or caching, to use an in-memory database that does not create any files:
For more store configuration options: for Java see the BoxStoreBuilder and for Dart the Store documentation. (Python APIs will be published soon)
Basic Box operations
The Box class is likely the class you interact with most. A Box instance gives you access to objects of a particular type. For example, if you have User and Order entities, you need a Box object to interact with each:
These are some of the operations offered by the Box class:
put inserts a new object or updates an existing one (with the same ID). When inserting, an ID will be assigned to the just inserted object (this will be explained below) and returned. put also supports putting multiple objects, which is more efficient.
get and getAll: Given an object’s ID, get reads it from its box. To get all objects in the box use getAll .
query: Starts building a query to return objects from the box that match certain conditions. See queries for details.
remove and removeAll: Remove a previously put object from its box (deletes it). remove also supports removing multiple objects, which is more efficient. removeAll removes (deletes) all objects in a box.
count: Returns the number of objects stored in this box.
For a complete list of methods available in the Box class, check the API reference documentation for Java or Dart.
Asynchronous operations
ObjectBox has built-in support to run (typically multiple or larger) database operations asynchronously.
runInTxAsync and callInTxAsync: runs the given Runnable/Callable in a transaction on a background thread (the internal ObjectBox thread pool) and calls the given callback once done. In case of callInTxAsync the callback also receives the returned result.
newCachedThreadPoolExecutor and newFixedThreadPoolExecutor: create an ObjectBoxThreadPoolExecutor to asynchronously execute ObjectBox operations. This default thread pool executor implementation properly cleans up thread-local ObjectBox resources. Use this if the async methods above don't work for your use case or your code needs full control over the thread pool.
Kotlin Coroutines
awaitCallInTx: wraps callInTxAsync in a coroutine that suspends until the transaction has completed. Likewise, on success the return value of the given callable is returned, on failure an exception is thrown.
newCachedThreadPoolDispatcher and newFixedThreadPoolDispatcher: create a coroutine dispatcher backed by an ObjectBoxThreadPoolExecutor to asynchronously execute ObjectBox operations. The executor properly cleans up thread-local ObjectBox resources. For example, use it instead of Dispatchers.IO when doing ObjectBox operations in coroutines.
Most Box methods do have async versions which run the operation in a worker isolate.
For example putAsync: asynchronously inserts a new object or updates an existing one (with the same ID). The returned future completes when the object is successfully written to the database.
To run multiple operations, it is more efficient to wrap the synchronous calls in an asynchronous transaction with runInTransactionAsync (API reference): run a callback with multiple database operations within a write or read transaction in the background without blocking the user interface. Can return results.
There is also runAsync (API reference): like runInTransactionAsync but does not start a transaction, leaving that to your callback code. This allows to supply a callback that is an async function.
If it is necessary to call put many times in a row, take a look at putQueued: Schedules the given object to be put later on, by an asynchronous queue, returns the id immediately even though the object may not have been written yet. You can use Store's awaitQueueCompletion() or awaitQueueSubmitted() to wait for the async queue to finish.
Currently work in progress.
Object IDs
By default IDs for new objects are assigned by ObjectBox. When a new object is put, it will be assigned the next highest available ID:
For example, if there is an object with ID 1 and another with ID 100 in a box, the next new object that is put will be assigned ID 101.
If you try to assign a new ID yourself and put the object, ObjectBox will throw an error.
If you need to assign IDs by yourself, have a look at how to switch to self-assigned IDs and what side effects apply.
Reserved Object IDs
Object IDs can not be:
0(zero) ornull(if using java.lang.Long) As said above, when putting an object with ID zero it will be assigned an unused ID (not zero).0xFFFFFFFFFFFFFFFF(-1 in Java) Reserved for internal use.
For a detailed explanation see the page on Object IDs.
Transactions
While ObjectBox offers powerful transactions, it is sufficient for many apps to consider just some basics guidelines about transactions:
A
putruns an implicit transaction.Prefer
putbulk overloads for lists (likeput(entities)) when possible.For a high number of DB interactions in loops, consider explicit transactions, such as using
runInTx().
For more details check the separate transaction documentation.
Have an app with greenDAO? DaoCompat is for you!
DaoCompat is a compatibility layer that gives you a greenDAO like API for ObjectBox. It makes switching from greenDAO to ObjectBox simple. Have a look at the documentation and the example. Contact us if you have any questions!
Next steps
Check out the ObjectBox example projects on GitHub.
Learn how to write unit tests.
To enable debug mode and for advanced use cases, see the Advanced Setup page.
Last updated
Was this helpful?