
Embed a tiny HTTP server in an app to browse SQLite databases via a web UI: inspect tables/views, run raw SQL, view schema, decode JSON, auto-reload, multi-database support.
Browse the SQLite databases inside your running app from a web browser. SQLite Web Viewer embeds a tiny HTTP server in your application that serves a web UI (built with SolidJS) for inspecting tables, running queries, and viewing schema — no need to pull the database file off the device.
It is published as a Kotlin Multiplatform library, so the same viewer runs on Android, JVM, and iOS.
┌─────────────┐ HTTP ┌──────────────────────────┐
│ Browser │◄──────────► │ Embedded server (Ktor) │
│ (web UI) │ /query │ in your app process │
└─────────────┘ └────────────┬─────────────┘
│ Queryable
▼
Your SQLite db(s)
Your app supplies one or more Queryables (an abstraction over "run these SQL
statements in a transaction"). The library serves the bundled web UI and proxies
its queries to your databases.
The library is published to Maven Central (see PUBLISHING.md):
dependencies {
implementation("io.github.simophin:sqlite-web-viewer:<version>")
}val queryable = SupportQueryable(myOpenHelper.writableDatabase)
val instance = startDatabaseViewerServer(
context = this, // an Activity
port = 3000,
queryable = queryable,
)
// Later, to shut it down:
instance.stop()Then open http://<device-ip>:3000/ in a browser (e.g. via adb forward tcp:3000 tcp:3000 and visit http://localhost:3000/).
Instead of a fixed set, provide a QueryableFactory. It is consulted afresh on
every request, so the available databases can change at runtime, and each
Queryable is only resolved when a request actually targets it (handy for
opening connections on demand):
val factory = object : QueryableFactory {
override fun databaseIds() = listOf("users", "products", "logs")
override fun queryableFor(id: String): Queryable? = when (id) {
"users" -> SupportQueryable(usersDb)
"products" -> SupportQueryable(productsDb)
"logs" -> SupportQueryable(logsDb)
else -> null // → 404
}
}
val instance = startDatabaseViewerServer(
context = this,
port = 3000,
factory = factory,
)This serves an index at / linking to /users/, /products/, and /logs/,
each with its own viewer. If you already hold every database up front, the map
form is equivalent:
startDatabaseViewerServer(
context = this,
port = 3000,
factory = QueryableFactory(mapOf("users" to usersQueryable, /* ... */)),
)See demoapp for a runnable example serving several
in-memory databases.
val driver = BundledSQLiteDriver()
val queryable = SqliteQueryable { driver.open(":memory:") }
val instance = startDatabaseViewerServerShared(
port = 3000,
queryable = queryable, // or: databases = mapOf(...)
assetProvider = ClasspathStaticAssetProvider(),
)The JVM module also has a runnable main (./gradlew :sqlite-web-viewer:jvmRun),
configurable via the DB_PATH environment variable.
startDatabaseViewerServer(port = 3000, queryable = queryable)The web UI is served from the app bundle via NSBundleAssetProvider.
The web UI must be built before the library, since its bundle is packaged into the artifact:
cd webapp
npm ci
npm run build
cd ../android_lib
./gradlew :sqlite-web-viewer:publishToMavenLocal # or build the demo appwebapp/ — the SolidJS web UI (README)android_lib/library/ — the Kotlin Multiplatform embedded-server libraryandroid_lib/demoapp/ — an Android sample appBrowse the SQLite databases inside your running app from a web browser. SQLite Web Viewer embeds a tiny HTTP server in your application that serves a web UI (built with SolidJS) for inspecting tables, running queries, and viewing schema — no need to pull the database file off the device.
It is published as a Kotlin Multiplatform library, so the same viewer runs on Android, JVM, and iOS.
┌─────────────┐ HTTP ┌──────────────────────────┐
│ Browser │◄──────────► │ Embedded server (Ktor) │
│ (web UI) │ /query │ in your app process │
└─────────────┘ └────────────┬─────────────┘
│ Queryable
▼
Your SQLite db(s)
Your app supplies one or more Queryables (an abstraction over "run these SQL
statements in a transaction"). The library serves the bundled web UI and proxies
its queries to your databases.
The library is published to Maven Central (see PUBLISHING.md):
dependencies {
implementation("io.github.simophin:sqlite-web-viewer:<version>")
}val queryable = SupportQueryable(myOpenHelper.writableDatabase)
val instance = startDatabaseViewerServer(
context = this, // an Activity
port = 3000,
queryable = queryable,
)
// Later, to shut it down:
instance.stop()Then open http://<device-ip>:3000/ in a browser (e.g. via adb forward tcp:3000 tcp:3000 and visit http://localhost:3000/).
Instead of a fixed set, provide a QueryableFactory. It is consulted afresh on
every request, so the available databases can change at runtime, and each
Queryable is only resolved when a request actually targets it (handy for
opening connections on demand):
val factory = object : QueryableFactory {
override fun databaseIds() = listOf("users", "products", "logs")
override fun queryableFor(id: String): Queryable? = when (id) {
"users" -> SupportQueryable(usersDb)
"products" -> SupportQueryable(productsDb)
"logs" -> SupportQueryable(logsDb)
else -> null // → 404
}
}
val instance = startDatabaseViewerServer(
context = this,
port = 3000,
factory = factory,
)This serves an index at / linking to /users/, /products/, and /logs/,
each with its own viewer. If you already hold every database up front, the map
form is equivalent:
startDatabaseViewerServer(
context = this,
port = 3000,
factory = QueryableFactory(mapOf("users" to usersQueryable, /* ... */)),
)See demoapp for a runnable example serving several
in-memory databases.
val driver = BundledSQLiteDriver()
val queryable = SqliteQueryable { driver.open(":memory:") }
val instance = startDatabaseViewerServerShared(
port = 3000,
queryable = queryable, // or: databases = mapOf(...)
assetProvider = ClasspathStaticAssetProvider(),
)The JVM module also has a runnable main (./gradlew :sqlite-web-viewer:jvmRun),
configurable via the DB_PATH environment variable.
startDatabaseViewerServer(port = 3000, queryable = queryable)The web UI is served from the app bundle via NSBundleAssetProvider.
The web UI must be built before the library, since its bundle is packaged into the artifact:
cd webapp
npm ci
npm run build
cd ../android_lib
./gradlew :sqlite-web-viewer:publishToMavenLocal # or build the demo appwebapp/ — the SolidJS web UI (README)android_lib/library/ — the Kotlin Multiplatform embedded-server libraryandroid_lib/demoapp/ — an Android sample app