{"id":32143305,"url":"https://github.com/lighter-swift/lighter","last_synced_at":"2025-10-21T07:56:52.908Z","repository":{"id":56794910,"uuid":"519749041","full_name":"Lighter-swift/Lighter","owner":"Lighter-swift","description":"Swift APIs for SQLite: Type-safe down to the schema. Very, very, fast. Dependency free.","archived":false,"fork":false,"pushed_at":"2025-10-03T13:18:59.000Z","size":635,"stargazers_count":498,"open_issues_count":21,"forks_count":14,"subscribers_count":7,"default_branch":"develop","last_synced_at":"2025-10-21T07:56:36.794Z","etag":null,"topics":["code-generation","database","spm-plugin","sqlite","swift"],"latest_commit_sha":null,"homepage":"https://lighter-swift.github.io/documentation/lighter/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lighter-swift.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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":"2022-07-31T10:51:26.000Z","updated_at":"2025-10-14T12:34:06.000Z","dependencies_parsed_at":"2025-10-03T15:24:28.432Z","dependency_job_id":null,"html_url":"https://github.com/Lighter-swift/Lighter","commit_stats":{"total_commits":137,"total_committers":6,"mean_commits":"22.833333333333332","dds":0.1970802919708029,"last_synced_commit":"3778a4e8ba40d36c75408c189ff550e28ab0e890"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/Lighter-swift/Lighter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lighter-swift%2FLighter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lighter-swift%2FLighter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lighter-swift%2FLighter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lighter-swift%2FLighter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lighter-swift","download_url":"https://codeload.github.com/Lighter-swift/Lighter/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lighter-swift%2FLighter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280225808,"owners_count":26293888,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-generation","database","spm-plugin","sqlite","swift"],"created_at":"2025-10-21T07:56:47.769Z","updated_at":"2025-10-21T07:56:52.897Z","avatar_url":"https://github.com/Lighter-swift.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch2\u003eLighter\r\n  \u003cimg src=\"https://zeezide.com/img/lighter/Lighter256.png\"\r\n       align=\"right\" width=\"64\" height=\"64\" /\u003e\r\n\u003c/h2\u003e\r\n\r\n**Lighter** is a set of technologies applying code generation to access \r\n[SQLite3](https://www.sqlite.org) databases from \r\n[Swift](https://swift.org/), e.g. in iOS applications or on the server.\r\nLike [SwiftGen](https://github.com/SwiftGen/SwiftGen) but for SQLite3.\r\n\r\n\u003cdetails\u003e\u003csummary\u003eType-safe down to the SQL schema.\u003c/summary\u003e\r\nState of the art: Developer writes Swift structures that match a SQLite \r\ntable. \r\nEnlighter reverses this, the generated Swift code reflects what the SQLite \r\ntable is actually defined as. No place for mistakes. \r\nRemove a “somewhere” in the “it’s always any-o-clock somewhere in the stack”.\r\n\u003c/details\u003e\r\n\u003cdetails\u003e\u003csummary\u003eVery, \u003cb\u003every\u003c/b\u003e, \u003ca href=\"https://github.com/Lighter-swift/PerformanceTestSuite\"\u003efast\u003c/a\u003e.\u003c/summary\u003e\r\nLighter builds upon the database schema and hence directly knows what \r\nit looks like at compile time. For common operations no mapping is \r\nnecessary at all, the generated code runs as fast (usually faster) than \r\nhand written code. It directly binds Swift structures to the SQLite API.\r\n\u003c/details\u003e\r\n\u003cdetails\u003e\u003csummary\u003eDependency free.\u003c/summary\u003e\r\nLighter itself is a small and convenient API to access SQLite databases. \r\nEnlighter, the code generator, can however produce code that just uses \r\nthe SQLite API and doesn’t require any dependencies, i.e. tech debt. \r\nDon’t ship 3rd party libraries, directly generate the necessary code \r\ninto your app.\r\n\u003c/details\u003e\r\n\r\nLighter is useful for two main scenarios:\r\n\r\n\u003cdetails\u003e\u003csummary\u003eShipping SQLite databases within your app (e.g. containing a product database).\u003c/summary\u003e\r\n\r\nSQLite databases are very resource efficient way to ship and access small\r\nand big amounts of data. As an alternative to bundling JSON resources files that\r\nare large and have to be parsed fully into memory on each start.\r\n\r\nWith a SQLite database only the required data needs to be loaded and the database files\r\nare extremely compact (e.g. no duplicate keys).\r\n\r\n\u003e SQLite database are also efficient and useful for downloading\r\n\u003e data from the network!\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\u003csummary\u003eMaintaining a fast local SQL cache or database.\u003c/summary\u003e\r\n\r\nIf the needs are simpler than a full \r\n[ORM](https://en.wikipedia.org/wiki/Object–relational_mapping)\r\nlike\r\n[CoreData](https://developer.apple.com/documentation/coredata), Lighter can be a great way to produce neat and typesafe\r\nAPIs for local caches or databases.\r\nIt is basic but convenient to use and very very fast as no runtime mapping\r\nor parsing has to happen at all. The code directly binds the generated\r\nstructures to the SQLite API.\r\n\r\nDatabases can be created on the fly or from prefilled database files shipped\r\nas part of the application resources.\r\n\r\n\u003e Linux is also supported, and Lighter can be a great choice for simple servers that\r\n\u003e primarily access a readonly set or run on a single host.\r\n\u003c/details\u003e\r\n\r\n### Overview\r\n\r\nLighter works the reverse from other \"mapping\" tools or SQLite wrappers. Instead of\r\nwriting Swift code that generates SQLite tables dynamically, Lighter generates Swift\r\ncode _for a_ SQLite database.\r\nEither literally from SQLite database files, or from SQL files that create SQLite\r\ndatabases.\r\n\r\n\u003cdetails open\u003e\r\n\u003csummary\u003eSmall Example Database (stored in either a SQLite db or created from .sql files):\u003c/summary\u003e\r\n  \r\n```sql\r\nCREATE TABLE person (\r\n  person_id INTEGER PRIMARY KEY NOT NULL,\r\n  name      TEXT NOT NULL,\r\n  title     TEXT NULL\r\n);\r\n\r\nCREATE TABLE address (\r\n  address_id INTEGER PRIMARY KEY NOT NULL,\r\n  \r\n  street  VARCHAR NULL,\r\n  city    VARCHAR NULL,\r\n  \r\n  person_id INTEGER,\r\n  FOREIGN KEY(person_id) REFERENCES person(person_id) ON DELETE CASCADE DEFERRABLE\r\n);\r\n```\r\n\r\nCan be converted to a structure like this (in a highly \r\n[configurable](https://lighter-swift.github.io/documentation/lighter/configuration)\r\nway):\r\n```swift\r\nstruct ContactsDB {\r\n\r\n  struct Person: Identifiable, Hashable {\r\n    var id       : Int\r\n    var name     : String\r\n    var title    : String?\r\n  }\r\n\r\n  struct Address: Identifiable, Hashable {\r\n    var id       : Int\r\n    var street   : String?\r\n    var city     : String?\r\n    var personId : Int?\r\n  }\r\n}\r\n```\r\n\r\nThe code generator can either generate dependency free code that only uses\r\nthe raw SQLite3 API or code that uses the \r\n[Lighter](https://github.com/Lighter-swift/Lighter/tree/develop/Sources/Lighter/) \r\nlibrary.\r\nThe Lighter library is not an\r\n[ORM](https://en.wikipedia.org/wiki/Object–relational_mapping),\r\nbut just a set of Swift protocols that allow for typesafe queries\r\n(and it is only intended to be used to support the code generator, not as a\r\n standalone library).\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\u003csummary\u003eHow does the code generation work?\u003c/summary\u003e\u003cbr/\u003e\r\n\r\nThe setup is intended to work with the new\r\n[Swift Package Plugins](https://developer.apple.com/videos/play/wwdc2022/110359/)\r\nfeature of the\r\n[Swift Package Manager](https://www.swift.org/package-manager/),\r\navailable since Swift 5.6 (and exposed in Xcode 14+).\r\nIf SPM plugins cannot be used yet, the\r\n[sqlite2swift](https://github.com/Lighter-swift/Lighter/tree/develop/Plugins/Tools/sqlite2swift/)\r\ntool can be called directly as well.\u003cbr\u003e\r\nIf you want to support the project, there is also the\r\n[Code for SQLite3](https://apps.apple.com/us/app/code-for-sqlite3/id1638111010/)\r\napp on the Mac AppStore. It does the same code generation as this FOSS project\r\nin a little more interactive way.\r\n\r\nThe Lighter package comes with a \"build tool plugin\" called \r\n[Enlighter](https://github.com/Lighter-swift/Lighter/tree/develop/Plugins/Enlighter/),\r\nthat automatically integrates the code generation results into the build process.\r\nIf it is added to a target, it'll scan for databases and SQL files and create the\r\nSwift accessors for them:\r\n```swift\r\n.target(name: \"ContactsDB\", dependencies: [ \"Lighter\" ],\r\n        resources: [ .copy(\"ContactsDB.sqlite3\") ],\r\n        plugins: [ \"Enlighter\" ]) // \u003c== tell SPM to use Enlighter on this target\r\n```\r\nThis variant is fully automatic, i.e. other code within the `ContactsDB` target\r\nhas direct access to the database types (e.g. the `Person` struct above).\r\n\r\nAs a manual alternative the\r\n[Generate Code for SQLite](https://github.com/Lighter-swift/Lighter/tree/develop/Plugins/GenerateCodeForSQLite/)\r\n\"command plugin\" is provided.\r\nThis plugin does the same generation as Enlighter, but is explicitly run by the\r\ndeveloper using the Xcode \"File / Packages\" menu. It places the resulting code\r\ninto the \"Sources\" folder of the app (where it can be inspected or modified).\r\n\u003c/details\u003e\r\n\r\n\u003cdetails open\u003e\u003csummary\u003eAccessing a database using the higher level Lighter API\u003c/summary\u003e\r\n\r\n```swift\r\n// Open a SQLite database embedded in the module resources:\r\nlet db = ContactsDB.module!\r\n\r\n// Fetch the number of records:\r\nprint(\"Total number of people stored:\", \r\n      try db.people.fetchCount())\r\n\r\n// There are various ways to filter, including a plain Swift closure:\r\nlet people = try db.people.filter { person in\r\n  person.title == nil\r\n}\r\n\r\n// Primary \u0026 foreign keys are directly supported:\r\nlet person    = try db.people.find(1)\r\nlet addresses = try db.addresses.fetch(for: person)\r\n\r\n// Updates can be done one-shot or, better, using a transaction:\r\ntry await db.transaction { tx in\r\n  var person = try tx.people.find(2)!\r\n  \r\n  // Update a record.\r\n  person.title = \"ZEO\"\r\n  try tx.update(person)\r\n\r\n  // Delete a record.\r\n  try tx.delete(person)\r\n  \r\n  // Reinsert the same record\r\n  let newPerson = try tx.insert(person) // gets new ID!\r\n}\r\n```\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n\u003csummary\u003eFetching Individual Columns\u003c/summary\u003e\u003cbr/\u003e\r\n\r\nOne of the advantages of SQL is that individual columns can be selected\r\nand updated for maximum efficiency. Only things that are\r\nrequired need to be fetched (vs. full records):\r\n```swift\r\n// Fetch just the `id` and `name` columns:\r\nlet people = try await db.select(from: \\.people, \\.id, \\.name) {\r\n  $0.id \u003e 2 \u0026\u0026 $0.title == nil\r\n}\r\n\r\n// Bulk update a specific column:\r\ntry db.update(\\.people, set: \\.title, to: nil, where: { record in\r\n  record.name.hasPrefix(\"Duck\")\r\n})\r\n```\r\n\r\nThe references are fully typesafe down to the schema, only columns\r\ncontained in the `person` table can be specified.\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\r\n\u003csummary\u003eDependency free SQLite3 API\u003c/summary\u003e\u003cbr/\u003e\r\n\r\nThe toolkit is also useful for cases in which the extra dependency on\r\nLighter is not desirable. For such the generator can\r\nproduce database specific Swift APIs that work alongside the regular\r\nSQLite API.\r\n```swift\r\n// Open the database, can also just use `sqlite3_open_v2`:\r\nvar db : OpaquePointer!\r\nsqlite3_open_contacts(\"contacts.db\", \u0026db)\r\ndefer { sqlite3_close(db) }\r\n\r\n// Fetch a person by primary key:\r\nlet person = sqlite3_person_find(db, 2)\r\n  \r\n// Fetch and filter people:\r\nlet people = sqlite3_people_fetch(db) {\r\n  $0.name.hasPrefix(\"Ja\")\r\n}\r\n\r\n// Insert a record\r\nvar person = Person(id: 0, name: \"Jason Bourne\")\r\nsqlite3_person_insert(db, \u0026person)\r\n```\r\n\r\nThere is another style the code generator can produce, it attaches the same\r\nfunctions to the generated types, e.g.:\r\n```swift\r\nlet people = Person.fetch(in: db) { $0.name.hasPrefix(\"So\") }\r\nvar person = Person.find(2, in: db)\r\n\r\nperson.name = \"Bourne\"\r\nperson.update(in: db)\r\nperson.delete(in: db)\r\nperson.insert(into: db)\r\n```\r\n\r\nThe main advantage of using the raw API is that no extra dependency\r\nis necessary at all. The generated functions are completely\r\nself-contained and can literally be copied\u0026pasted into places where\r\nneeded.\r\n\u003c/details\u003e\r\n\r\n\u003cdetails\u003e\u003csummary\u003eBeautiful, autogenerated DocC API Comments\u003c/summary\u003e\u003cbr/\u003e\r\nThe Lighter code generator can also generate API comments for the database\r\ntypes.\r\n\r\nExample: [Northwind Database](https://Northwind-swift.github.io/NorthwindSQLite.swift/documentation/northwind/employee).\r\n  \r\n\u003cimg src=\"https://zeezide.com/img/lighter/docc-record-type.png\" /\u003e\r\n\u003cimg src=\"https://zeezide.com/img/lighter/docc-target.png\" /\u003e\r\n\r\n\u003c/details\u003e\r\n\r\n\r\nInterested? 👉 [Getting Started](https://lighter-swift.github.io/documentation/lighter/gettingstarted).\r\n\r\n\r\n### Who\r\n\r\nLighter is brought to you by\r\n[Helge Heß](https://github.com/helje5/) / [ZeeZide](https://zeezide.de).\r\nWe like feedback, GitHub stars, cool contract work, \r\npresumably any form of praise you can think of.\r\n\r\n**Want to support my work**?\r\nBuy an [app](https://zeezide.de/en/products/products.html):\r\n[Code for SQLite3](https://apps.apple.com/us/app/code-for-sqlite3/id1638111010/),\r\n[Past for iChat](https://apps.apple.com/us/app/past-for-ichat/id1554897185),\r\n[SVG Shaper](https://apps.apple.com/us/app/svg-shaper-for-swiftui/id1566140414),\r\n[HMScriptEditor](https://apps.apple.com/us/app/hmscripteditor/id1483239744).\r\nYou don't have to use it! 😀\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flighter-swift%2Flighter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flighter-swift%2Flighter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flighter-swift%2Flighter/lists"}