VectorLite is an Android library for local relational data, CRUD services, reactive table changes, and vector search — all on-device.
It is designed for apps that need:
- clean entity mapping
- simple CRUD access
- custom service layers
- query DSLs
- vector embeddings
- relationships between tables
- transactions
- backup and restore
- SQLite extensions
repositories {
maven("https://jitpack.io")
}dependencies {
implementation("com.github.kkokotero:VectorLite:1.0.0")
}Most Android apps end up splitting persistence into several layers:
Database
↓
Repository
↓
Service
↓
Business logic
↓
Vector search integrationVectorLite keeps that flow in one library:
VectorLite
├── Entities
├── CRUD
├── Repositories
├── Services
├── Relations
├── Vector search
├── Triggers
└── Backup / restoreimport io.github.kkokotero.vectorlite.orm.Column
import io.github.kkokotero.vectorlite.orm.DataTable
import io.github.kkokotero.vectorlite.orm.ForeignKey
import io.github.kkokotero.vectorlite.orm.Relationship
import io.github.kkokotero.vectorlite.orm.RelationshipType
import io.github.kkokotero.vectorlite.orm.VectorColumn
@DataTable("users")
data class UserEntity(
@Column(primaryKey = true, autoIncrement = true, nullable = false)
val id: Long = 0,
@Column(nullable = false, unique = true)
val email: String,
@Column(nullable = false)
val name: String
)
@DataTable("face_embeddings")
data class FaceEmbeddingEntity(
@Column(primaryKey = true, autoIncrement = true, nullable = false)
val id: Long = 0,
@ForeignKey(entity = UserEntity::class)
@Column(nullable = false)
val userId: Long,
@VectorColumn(dimensions = 512, elementSize = 4)
val embedding: FloatArray
)If you do not set a name, VectorLite uses the app label by default.
import io.github.kkokotero.vectorlite.VectorLite
val db = VectorLite.database(context) {
entities(
UserEntity::class,
FaceEmbeddingEntity::class
)
services(
FaceRecognitionService::class
)
}val users = db.crud<UserEntity>()
val embeddings = db.repository<FaceEmbeddingEntity>()
val faceService = db.service<FaceRecognitionService>()Use crud<T>() when you want a simple table-oriented service.
val users = db.crud<UserEntity>()
users.create(
UserEntity(name = "Kevin", email = "kevin@example.com")
)
val kevin = users.first {
UserEntity::email equal "kevin@example.com"
}
val allUsers = users.findAll()If you want lower-level access and batch helpers, use repository<T>().
val embeddings = db.repository<FaceEmbeddingEntity>()
embeddings.insertAll(
FaceEmbeddingEntity(userId = 1, embedding = queryVector),
FaceEmbeddingEntity(userId = 2, embedding = otherVector)
)Custom services are the recommended place for business logic.
import io.github.kkokotero.vectorlite.DefaultTableService
import io.github.kkokotero.vectorlite.Repository
import io.github.kkokotero.vectorlite.Service
import io.github.kkokotero.vectorlite.VectorLiteSession
import io.github.kkokotero.vectorlite.orm.Table
@Service
class FaceRecognitionService(
table: Table<FaceEmbeddingEntity>,
session: VectorLiteSession,
private val embeddings: Repository<FaceEmbeddingEntity>
) : DefaultTableService<FaceEmbeddingEntity>(table, session) {
fun storeEmbedding(userId: Long, vector: FloatArray): FaceEmbeddingEntity {
return create(
FaceEmbeddingEntity(
userId = userId,
embedding = vector
)
)
}
}Usage:
val service = db.service<FaceRecognitionService>()
service.storeEmbedding(userId = 1, vector = embedding)val users = db.crud<UserEntity>()
val kevin = users.first {
UserEntity::name equal "Kevin"
}
val matchedUsers = users.where {
UserEntity::email matches "%@example.com"
}Available operators:
equalnotEqualgreaterThangreaterThanOrEquallessThanlessThanOrEqualmatchesinside
val results = db.repository<FaceEmbeddingEntity>()
.query()
.nearestTo(
column = FaceEmbeddingEntity::embedding,
vector = queryVector,
options = io.github.kkokotero.vectorlite.orm.VectorSearchOptions(
topK = 5,
approximate = true
)
)
.vectorSearch()
val bestMatch = results.bestMatchIf you only need the closest result:
val match = db.table<FaceEmbeddingEntity>().nearestNeighbor(
vectorColumn = FaceEmbeddingEntity::embedding,
queryVector = queryVector
)@DataTable("users")
data class UserEntity(
@Column(primaryKey = true, autoIncrement = true, nullable = false)
val id: Long = 0,
@Column(nullable = false)
val name: String,
@Relationship(
targetEntity = FaceEmbeddingEntity::class,
type = RelationshipType.ONE_TO_MANY,
mappedBy = "userId"
)
var embeddings: List<FaceEmbeddingEntity> = emptyList()
)Relationships can be loaded automatically through the query API.
db.transaction {
val users = db.repository<UserEntity>()
val embeddings = db.repository<FaceEmbeddingEntity>()
val userId = users.insert(
UserEntity(name = "Kevin", email = "kevin@example.com")
)
embeddings.insert(
FaceEmbeddingEntity(
userId = userId,
embedding = queryVector
)
)
}Batch helpers such as insertAll() and upsertAll() already run inside a transaction.
db.tableChanges("users").collect { event ->
println("${event.tableName} changed: ${event.operation}")
}Typed triggers:
db.triggers.afterInsert<UserEntity> {
println("User inserted")
}
db.triggers.afterUpdate<UserEntity> {
println("User updated")
}
db.triggers.afterDelete<UserEntity> {
println("User deleted")
}import java.io.File
db.exportTo(File(context.filesDir, "vectorlite-backup.db"))
db.importFrom(File(context.filesDir, "vectorlite-backup.db"))app/
├── data/
│ ├── entities/
│ ├── services/
│ └── database/
└── ui/For a public library, keep the demo app focused on real usage and keep the library code small and readable.
- face recognition
- semantic search
- local AI memory
- offline-first apps
- embedded catalogs
- relationship-heavy data models
| Feature | Room | VectorLite |
|---|---|---|
| Relational data | ✓ | ✓ |
| Type-safe Kotlin API | ✓ | ✓ |
| Built-in CRUD service layer | Partial | ✓ |
| Vector search | No | ✓ |
| Reactive table changes | Limited | ✓ |
| SQLite extensions | Limited | ✓ |
| On-device AI workloads | No | ✓ |
| Feature | sqlite-vector | VectorLite |
|---|---|---|
| Vector search | ✓ | ✓ |
| ORM | No | ✓ |
| Relations | No | ✓ |
| Services | No | ✓ |
| Query DSL | No | ✓ |
| Android-friendly API | Low-level | High-level |
| Feature | ObjectBox | VectorLite |
|---|---|---|
| Local database | ✓ | ✓ |
| Vector search | ✓ | ✓ |
| SQLite based | No | ✓ |
| SQL access | Limited | ✓ |
| Custom SQLite extensions | No | ✓ |
| Service layer | Manual | Built-in |
- Android-only
- minSdk 27
- Kotlin 17
- AndroidX bundled SQLite
VectorLite is under active development.
The API is intended to stay clean and public-facing, but it may still evolve before the first stable release.
See CONTRIBUTING.md.
See CODE_OF_CONDUCT.md.
See LICENSE.