{"id":33914499,"url":"https://github.com/mobiletoly/sqlitenow-kmp","last_synced_at":"2026-01-27T01:12:23.324Z","repository":{"id":298111613,"uuid":"998541260","full_name":"mobiletoly/sqlitenow-kmp","owner":"mobiletoly","description":"SQLiteNow - Build type-safe Kotlin APIs from SQLite","archived":false,"fork":false,"pushed_at":"2026-01-11T04:41:01.000Z","size":1858,"stargazers_count":48,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-11T12:09:50.546Z","etag":null,"topics":["code-generator","kmp","kotlin","multiplatform","sql","sqlitenow","type-safe"],"latest_commit_sha":null,"homepage":"https://mobiletoly.github.io/sqlitenow-kmp/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mobiletoly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-08T20:35:57.000Z","updated_at":"2026-01-11T04:41:04.000Z","dependencies_parsed_at":"2025-08-05T09:15:48.685Z","dependency_job_id":"9e299a37-828f-4d8b-9b21-c7c9b9995cd0","html_url":"https://github.com/mobiletoly/sqlitenow-kmp","commit_stats":null,"previous_names":["mobiletoly/sqlitenow-kmp"],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/mobiletoly/sqlitenow-kmp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobiletoly%2Fsqlitenow-kmp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobiletoly%2Fsqlitenow-kmp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobiletoly%2Fsqlitenow-kmp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobiletoly%2Fsqlitenow-kmp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mobiletoly","download_url":"https://codeload.github.com/mobiletoly/sqlitenow-kmp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobiletoly%2Fsqlitenow-kmp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28794976,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T01:07:07.743Z","status":"ssl_error","status_checked_at":"2026-01-27T01:07:06.974Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generator","kmp","kotlin","multiplatform","sql","sqlitenow","type-safe"],"created_at":"2025-12-12T06:30:44.954Z","updated_at":"2026-01-27T01:12:23.313Z","avatar_url":"https://github.com/mobiletoly.png","language":"Kotlin","readme":"# SQLiteNow\n\n[![Kotlin Multiplatform](https://img.shields.io/badge/Kotlin-Multiplatform-blue?logo=kotlin)](https://kotlinlang.org/docs/multiplatform.html)\n[![Maven Central](https://img.shields.io/maven-central/v/dev.goquick.sqlitenow/dev.goquick.sqlitenow.gradle.plugin?logo=apache-maven\u0026label=Maven%20Central)](https://central.sonatype.com/artifact/dev.goquick.sqlitenow/dev.goquick.sqlitenow.gradle.plugin)\n[![CI](https://img.shields.io/github/actions/workflow/status/mobiletoly/sqlitenow-kmp/gradle.yml?branch=main\u0026logo=github\u0026label=CI)](https://github.com/mobiletoly/sqlitenow-kmp/actions/workflows/gradle.yml)\n[![License](https://img.shields.io/github/license/mobiletoly/sqlitenow-kmp?logo=apache\u0026label=License)](LICENSE)\n\nA Kotlin Multiplatform library for type-safe, SQLite database access, inspired by SQLDelight.\nUnlike other popular frameworks (such as Room) - it is full SQL-first framework. Write your\nqueries in SQL files, get type-safe Kotlin code generated automatically. And no runtime annotations\noverhead, everything is generated at compile time.\n\n**Sync-Ready**: SQLiteNow includes a complete synchronization system for multi-device applications,\nallowing seamless data sync across devices with conflict resolution and offline-first capabilities.\n\n## Overview\n\nSQLiteNow generates Kotlin code from your SQL files, giving you full control over your queries\nwhile maintaining type safety. Unlike SQLDelight, which supports multiple database engines,\nSQLiteNow is focused exclusively on SQLite, allowing for deeper integration and SQLite-specific\noptimizations.\n\nFull documentation is available in the https://mobiletoly.github.io/sqlitenow-kmp/ pages.\n\nWhile we have added includes few sample projects to this repository, but for a very simple\nend-to-end walkthrough, follow the [Mood Tracker tutorial series](https://mobiletoly.github.io/sqlitenow-kmp/tutorials/) and browse the\naccompanying [sample project](https://github.com/mobiletoly/moodtracker-sample-kmp).\n\n## Key Features\n\n### Supported Platforms\n\n- Android (Kotlin/JVM via AndroidX bundled SQLite driver)\n- iOS (Kotlin/Native with bundled SQLite)\n- JVM desktop/server targets\n- JavaScript (browser) via SQL.js with optional IndexedDB persistence\n- Kotlin/Wasm (browser) using the same SQL.js runtime with automatic OPFS or IndexedDB persistence\n\n### Type-Safe SQL Generation\n\n- **Pure SQL Control** - Write your queries in SQL files, get type-safe Kotlin code\n- **Comment-based Annotations** - Control code generation using simple `-- @@{ annotations }`\n  comments in your SQL.\n- **No IDE Plugin Required** - Works with any editor, uses Gradle plugin for code generation\n- **Kotlin Multiplatform** - Targets Android, iOS, JVM, JavaScript, and Kotlin/Wasm browsers\n  using [androidx.sqlite](https://developer.android.com/kotlin/multiplatform/sqlite) driver plus SQL.js where appropriate\n- **SQLite Focused** - Optimized specifically for SQLite features and capabilities\n- **Migration support** - Migration scripts are supported to manage database schema changes\n\n### Optional Multi-Device Synchronization\n\n- **Built-in Sync System** - Complete synchronization solution for multi-device applications\n- **Conflict Resolution** - Automatic conflict resolution with pluggable strategies (Server Wins,\n  Client Wins, etc.)\n- **Change Tracking** - Automatic tracking of INSERT, UPDATE, DELETE operations\n- **Offline-First** - Works seamlessly offline, syncs when connection is available\n- **JWT Authentication** - Secure sync with customizable authentication via HttpClient\n- **Incremental Sync** - Efficient sync with pagination and change-based updates\n\n\n## Components\n\nClient-side framework components:\n- **SQLiteNow Generator** - The code generation component of the SQLiteNow framework that\n  generates type-safe Kotlin code from SQL files.\n- **SQLiteNow Library** - The core library that provides convenient APIs for database access.\n- **OverSqlite** - The sync component of the SQLiteNow framework that enables seamless data\n  sharing across multiple devices with automatic conflict resolution, change tracking, and\n  offline-first capabilities.\n\nServer-side components:\n- **OverSync** - Sync server that provides an adapter library for data synchronization.\n  Currently we have **go-oversync** implementation in Go with PostgreSQL as data store.\n  Visit this link for more information: https://github.com/mobiletoly/go-oversync\n\n**It is important to mention** that you can use SQLiteNow Generator and SQLiteNow Library without\nusing OverSqlite for synchronization. And vice versa - you can use OverSqlite for synchronization\nof SQLite database with PostgreSQL without using SQLiteNow Generator and SQLiteNow Library.\n\n\n## Why SQLiteNow exists if SQLDelight is really awesome\n\nEven if you don't care about multi-device synchronization, SQLiteNow has few key differences\nfrom SQLDelight:\n\nFirst of all, I wanted to target specifically SQLite in Kotlin Multiplatform environment, it is my\nplatform of choice as of now for mobile development. SQLiteNow built on top of using multiplatform\nSQLite driver from AndroidX.\n\nSecond, since we use comment-based annotations, no plugin is required (like in case of SQLDelight),\nso you can easily use just a regular SQL files that will be validated by your IDE or other external\ntools for correctness.\n\nThird, I wanted to have a more flexible and extensible code generation system that can be easily\nextended and customized. I use hexagonal architecture in my code, but sometimes converting between\nmultiple layers is tiresome, so I wanted to have a way to generate code that will be very close\nto my domain layer, without sacrificing the ability to write pure SQL queries.\n\nHere is the brief example:\n\n```sqlite\n-- @@{ queryResult=PersonWithAddresses }\nSELECT p.id,\n       p.first_name,\n       p.last_name,\n       p.email,\n       p.created_at,\n\n       a.address_type,\n       a.postal_code,\n       a.country,\n       a.street,\n       a.city,\n       a.state\n\n/* @@{ dynamicField=addresses,\n       mappingType=collection,\n       propertyType=List\u003cAddress\u003e,\n       sourceTable=a,\n       collectionKey=address_id } */\n\nFROM Person p\n     LEFT JOIN PersonAddress a ON p.id = a.person_id\nORDER BY p.id, a.address_type\nLIMIT :limit OFFSET :offset\n```\n\nThis will generate **PersonWithAddresses** data class. This class has `addresses: List\u003cAddress\u003e`\nproperty that contains all home addresses for the person. Another class\n**PersonQuery.SelectAllWithAddresses.Params** will be generated as well with `limit` and `offset`\nparameters to pass parameters to the query.\n\nAnd you can define your own adapters to convert between SQLite and your domain types\nand register them for seamless integration. We provide few built-in adapters as well,\nsuch as converting from TEXT to Kotlin's date/time etc.\n\nYou can always shape your data even more with `mapTo` annotation.\n\n## How it works\n\n### Code Generation\n1. Write your SQL queries in `.sql` files\n2. Add annotations using SQL comments to control code generation\n3. Run the Gradle plugin to generate type-safe Kotlin code\n4. Use the generated database classes in your application\n\nFull examples is available in the [`/sample-kmp`](./sample-kmp) directory.\n\n## Multi-Device Synchronization (optional)\n\nSQLiteNow includes a complete synchronization system for building multi-device applications.\nSimply annotate your tables with `enableSync=true` and the sync system handles the rest:\n\n```sql\n-- Enable sync for this table\n-- @@{ enableSync=true }\nCREATE TABLE person (\n    id TEXT PRIMARY KEY NOT NULL,\n    first_name TEXT NOT NULL,\n    last_name TEXT NOT NULL,\n    email TEXT UNIQUE,\n    created_at INTEGER NOT NULL DEFAULT (unixepoch())\n);\n```\n\nThen use the generated sync client in your application:\n\n```kotlin\n// Create authenticated HTTP client with JWT token refresh and base URL\nval httpClient = HttpClient {\n    install(Auth) {\n        bearer {\n            loadTokens { /* load saved token */ }\n            refreshTokens { /* refresh when expired */ }\n        }\n    }\n    defaultRequest {\n        url(\"https://api.myapp.com\")\n    }\n}\n\n// Create sync client\nval syncClient = db.newOversqliteClient(\n    schema = \"myapp\",\n    httpClient = httpClient,\n    resolver = ServerWinsResolver\n)\n\n// Bootstrap new device\nsyncClient.bootstrap(userId = \"user123\", sourceId = \"device456\")\n\n// Perform full sync (upload local changes, download remote changes)\nval uploadResult = syncClient.uploadOnce()\nval downloadResult = syncClient.downloadOnce(limit = 500)\n```\n\nThe sync system automatically handles:\n- **Change tracking** for all sync-enabled tables\n- **Conflict resolution** when the same record is modified on multiple devices\n- **Incremental sync** to minimize bandwidth usage\n- **Error handling** and retry logic\n- **Authentication** via customizable HttpClient\n\nFull example is available in the [`/samplesync-kmp`](./samplesync-kmp) directory.\n\n## Documentation\n\nFull documentation is available in the https://mobiletoly.github.io/sqlitenow-kmp/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobiletoly%2Fsqlitenow-kmp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmobiletoly%2Fsqlitenow-kmp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobiletoly%2Fsqlitenow-kmp/lists"}