{"id":48289138,"url":"https://github.com/aleris/typeid-kotlin","last_synced_at":"2026-04-04T23:00:59.173Z","repository":{"id":240172097,"uuid":"801866173","full_name":"aleris/typeid-kotlin","owner":"aleris","description":"A Kotlin implementation of TypeID (Type-safe, K-sortable, globally unique identifier inspired by Stripe IDs).","archived":false,"fork":false,"pushed_at":"2024-11-29T13:57:06.000Z","size":623,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-29T14:44:28.732Z","etag":null,"topics":["typeid","uuidv7"],"latest_commit_sha":null,"homepage":"https://aleris.github.io/typeid-kotlin/","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/aleris.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}},"created_at":"2024-05-17T04:22:13.000Z","updated_at":"2024-11-29T13:57:10.000Z","dependencies_parsed_at":"2024-05-17T05:31:43.202Z","dependency_job_id":"77621f40-62bc-4913-a0dc-c5a9f5328273","html_url":"https://github.com/aleris/typeid-kotlin","commit_stats":null,"previous_names":["aleris/typeid-kotlin"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/aleris/typeid-kotlin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleris%2Ftypeid-kotlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleris%2Ftypeid-kotlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleris%2Ftypeid-kotlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleris%2Ftypeid-kotlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aleris","download_url":"https://codeload.github.com/aleris/typeid-kotlin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleris%2Ftypeid-kotlin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31418286,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T20:09:54.854Z","status":"ssl_error","status_checked_at":"2026-04-04T20:09:44.350Z","response_time":60,"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":["typeid","uuidv7"],"created_at":"2026-04-04T23:00:51.876Z","updated_at":"2026-04-04T23:00:59.160Z","avatar_url":"https://github.com/aleris.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typeid-kotlin\n![Build Status](https://github.com/aleris/typeid-kotlin/actions/workflows/build-on-push.yml/badge.svg)\n![Current Version](https://img.shields.io/badge/Version-1.0.1-blue)\n\n\n## A Kotlin implementation of [TypeID](https://github.com/jetpack-io/typeid).\n\nTypeIDs are a modern, type-safe, globally unique identifier based on the upcoming\nUUIDv7 standard. They provide a ton of nice properties that make them a great choice\nas the primary identifiers for your data in a database, APIs, and distributed systems.\nRead more about TypeIDs in their [spec](https://github.com/jetpack-io/typeid).\n\nBased on the Java implementation from [fxlae/typeid-java](https://github.com/fxlae/typeid-java).\n\nThis implementation adds a more complete type safety including id and their prefixes and uses an idiomatic Kotlin API.\n\n[API Documentation](https://aleris.github.io/typeid-kotlin/)\n\n\n## Dependency\n\nTo use with Maven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eearth.adi\u003c/groupId\u003e\n    \u003cartifactId\u003etypeid-kotlin\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nTo use via Gradle:\n\n```kotlin\nimplementation(\"earth.adi:typeid-kotlin:1.0.1\")\n```\n\n\n## Usage\n\nThe `TypeId` class is the main entry point for working with TypeIDs.\nThe class can be used to generate `Id` instances or parse them from strings.\nThey are typesafe, immutable and thread-safe.\n \n\n### Generating ids\n\nTo use the typed features of the library, you need to define your typed id associated with an entity.\n\n```kotlin\n// Define your identifiable entity type:\ndata class User(val id: UserId) // can contain other fields\n\n// Define a typealias for the user id.\ntypealias UserId = Id\u003cout User\u003e\n\n```\n\n\n#### generate\n\nTo generate a new `Id`, based on UUIDv7 as per specification:\n\n```kotlin\n// create a reusable TypeId instance, can be stored in a DI container\nval typeId = typeId()\n\nval userId: UserId = typeId.generate()\nprintln(userId) // prints something like user_01h455vb4pex5vsknk084sn02q\nprintln(typeId.typedPrefix.prefix) // \"user\"\nprintln(typeId.uuid) // java.util.UUID(01890a5d-ac96-774b-bcce-b302099a8057)\n```\n\nThis is inferring the Java type of the typeid to `UserId`.\n\nAlternatively, specifying the entity type, for example for `User`,\nwill also generate the associated id `UserId`:\n\n```kotlin\nval userId = typeId.generate\u003cUser\u003e()\n```\n\nOr specify the type explicitly, which can also be used from Java code as it does not rely on Kotlin type inference:\n\n```kotlin\nval userId = typeId.generate(User::class.java)\n```\n\nIf the type of the id can be inferred, it will also work seamlessly:\n\n```kotlin\ndata class User(val id: UserId)\nval user = User(typeId.generate()) // infers UserId\n```\n\nAlternatively, directly use the static methods in `TypeId`:\n    \n```kotlin\nval userId: UserId = TypeId.generate()\n```\n\nUsing an explicit string prefix will instead generate a `RawId`:\n\n```kotlin\nval rawId: RawId = typeId.generate(\"custom\")\nprintln(rawId) // prints something like custom_01h455vb4pex5vsknk084sn02q\n```\n\nRaw ids are just a string with a prefix and a UUID, without any Java/Kotlin type information, \nso it is better to use typed ids whenever possible (see [Type safety](#type-safety) below).\n\nAll methods described below also have raw variants.\n\n\n#### of\n\nTo construct (or reconstruct) an `Id` from an `UUID`:\n\n```kotlin\nval userId: UserId = typeId.of(someUUID)\n```\n\nor for a `RawId`:\n```kotlin\nval userId: RawId = TypeId.of(\"user\", someUUID)\n```\n\n\n### Parsing from strings\n\nFor parsing, the library supports both an imperative programming model and a more functional style.\n\n\n#### parse\n\nThe most straightforward way to parse the textual representation of an id:\n\n\n```kotlin\nval userId: UserId = typeId.parse(\"user_01h455vb4pex5vsknk084sn02q\")\n\n```\n\nInvalid inputs will result in an `IllegalArgumentException`, with a message explaining the cause of the parsing failure.\n\nTo parse a `RawId`:\n\n```kotlin\nval rawId: RawId = TypeId.parse(\"custom_01h455vb4pex5vsknk084sn02q\")\n```\n\nWill create a `RawId` instance with the prefix 'custom'.\n\n\n#### parseToValidated\n\nIf you prefer working with errors modeled as return values rather than exceptions, \nthis is also possible (and is *much* more performant for untrusted input with high error rates, \nas no stacktrace is involved):\n\n\n```kotlin\nval userId: UserId = typeId.parseToValidated(\"user_01h455vb4pex5vsknk084sn02q\")\n\nwhen(userId) {\n    is Validated.Valid -\u003e {\n        val userId = userId.id\n        // Proceed with userId\n    }\n    is Validated.Invalid -\u003e {\n        val error = userId.error\n        // Optionally, do something with the error message\n    }\n}\n```\n\nThe `Validated` class includes a couple of functional style helper methods like `filter` and `map`.\n\nExample:\n\n```kotlin\ntypeId\n  .parseToValidated\u003cUser\u003e(\"user_01h455vb4pex5vsknk084sn02q\")\n  .filter { it.id == idFromSomewhereElse }\n  .map { it.id }\n  .ifValid { println(\"Valid id: $it\") }\n```\n\nAnother safe alternative for working with validated is to use Kotlin functions like:\n\n```kotlin\nval id = typeId.parseToValidated\u003cUser\u003e(\"user_01h455vb4pex5vsknk084sn02q\")\n  .takeIf { it is Validated.Valid }\n  ?.let { it as Validated.Valid }\n  ?.id\nif (id != null) {\n  println(\"Valid id: $id\")\n}\n```\n\nThese approaches are much faster when the input is untrusted and can result in lots of exceptions otherwise \n(see [Benchmarks](#benchmarks)).\n\n\n### isId\n\nCheck if a string is a valid id of the given type:\n\n```kotlin\nval isUserId = typeId.isId\u003cUserId\u003e(\"user_01h455vb4pex5vsknk084sn02q\")\n```\n\nIs a convenience method that uses `parseToValidated` and returns a boolean.\nIt can be used to check if a string is a valid id of an expected type \nas it returns `false` if the id is valid but of a different type.\n\n\n### Type safety\n\nAt its base, a `typeid` is just a prefix followed by `_` and an encoded UUID \n(see the [spec](https://github.com/jetify-com/typeid/tree/main/spec)).\nAfter it is encoded is just a string.\n\nThis could result in bugs if you accidentally mix up ids from different entities.\n\n```kotlin\nval id: RawId = typeId.generate(\"user\")\n\n// ... sometime later\nval orgExists = someService.checkIfOrganizationExists(id)\n// returns false most of the time so the bug may be hard to find\n```\n\nThe library provides a type-safe way to work with these ids, by associating them with a specific type.\n\n1. Fail if unexpected prefix is used\n```kotlin\n// fails if id does not have a `user` prefix\nval userId: UserId = typeId.parse(id) \n```\n\n2. Compile time safety\n```kotlin\nval id: UserId = typeId.parse(text)\n\n// ... sometime later\nval orgExists = someService.checkIfOrganizationExists(id)\n// compile error, as id is of type `Id\u003cUser\u003e` (or `UserId` if using a typealias), \n// not Id\u003cOrganization\u003e\n```\n\n\n### Customizing prefixes\n\nThe `TypeId` class can be customized to use a specific prefix for the generated ids \nassociated with an entity type.\n\nFor example to register a custom prefix for the `Organization` entity:\n```kotlin\nval typeId = typeId().withCustomPrefix(TypedPrefix\u003cOrganization\u003e(\"org\"))\nprintln(typeId.generate\u003cOrganization\u003e()) // prints something like org_01h455vb4pex5vsknk084sn02q\n```\n\nAnother possibility is to add the `TypedPrefix` annotation to the entity instance:\n\n```kotlin\n@TypeIdPrefix(\"cust\")\ndata class Customer(override val id: CustomerId)\n```\n\nThis can also be useful when you want a different entity interface (maybe defined in a different module). \nFor example, define an interface with the `@TypeIdPrefix` annotation,\nwhich is implemented by the entity class:  \n\n```kotlin\n@TypeIdPrefix(\"cust\")\ninterface CustomerIdentifiable {\n  val id: CustomerId\n}\n\ntypealias CustomerId = Id\u003cout CustomerIdentifiable\u003e\n\ndata class Customer(override val id: CustomerId) : CustomerIdentifiable\n```\n\nIf the `@TypeIdPrefix` is present (on the entity or one of its interfaces) TypeId will use that. \nNote that the prefixes registered through the `TypeId` instance will take precedence \nover the ones defined with annotations, you should use just one of the two methods to define prefixes.\n\n\n### Customizing the UUID generator\n\nBy default, the library uses the `UUIDv7` generator, as per typeid specification,\nbut you can provide your own generator.\n\n```kotlin\n// use Java UUID random generator\nval typeId = typeId().withUUIDGenerator { UUID.randomUUID() }\n// or using com.fasterxml.uuid:java-uuid-generator\nval typeId = typeId().withUUIDGenerator { Generators.randomBasedGenerator().generate() }\n```\n\n\n### Serialization and deserialization\n\nThe ids in this library have built-in serialization and deserialization support\nfor Java, Kotlin (kotlinx.serialization), and Jackson.\n\n\n#### Kotlin (kotlinx.serialization)\n\nBoth `Id` and `RawId` have `@Serializable` and can be used with `kotlinx.serialization`.\nYou need to include the actual serialization dependency in your project.\n\nFor example, with CBOR:\n\n`include(\"io.github.microutils:kotlin-serialization-cbor:1.6.3\")`\n\n```kotlin\nval bytes = Cbor.encodeToByteArray\u003cId\u003cUser\u003e\u003e(id)\nval deserialized = Cbor.decodeFromByteArray\u003cId\u003cUser\u003e\u003e(bytes)\n```\n\n\n#### Jackson\n\nThe library provides a Jackson module to serialize and deserialize `Id` instances.\n\n```kotlin\nprivate val objectMapper = jacksonObjectMapper().registerModule(typeId.jacksonModule())\n\ndata class UserAndOrganization(\n  val user: User,\n  val organization: Organization,\n)\n\nval userAndOrganization =\n  UserAndOrganization(\n    User(typeId.parse\u003cUser\u003e(\"user_01hy0d96sgfx0rh975kqkspchh\")),\n    Organization(typeId.parse\u003cOrganization\u003e(\"org_01hy0sk45qfmdsdme1j703yjet\")),\n  )\nval writtenJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(userAndOrganization)\n// writes:\n// {\n//    \"user\" : {\n//      \"id\" : \"user_01hy0d96sgfx0rh975kqkspchh\"\n//    },\n//    \"organization\" : {\n//      \"id\" : \"org_01hy0sk45qfmdsdme1j703yjet\"\n//    }\n// }\n\nval read = objectMapper.readValue\u003cJsonUserAndOrganization\u003e(writtenJson)\n// read.user.id is same as typeId.parse\u003cUser\u003e(\"user_01hy0d96sgfx0rh975kqkspchh\")\n```\n\n\n## Using it with Spring\n\nSee [Spring Snippets](https://github.com/aleris/typeid-kotlin/wiki/Using-kotlin-TypeId-type‐safe-ids-with-Spring) \nfor examples on how to use `TypeId` with Spring Data and WebMvc by creating converters and formatters.\n\n\n## Building From Source\n \u003cdetails\u003e\n    \u003csummary\u003eDetails\u003c/summary\u003e\n\n```console\n~$ git clone https://github.com/aleris/typeid-kotlin.git\n~$ cd typeid-kotling\n~/typeid-kotlin sdk use java 17.0.9-tem\n~/typeid-kotlin ./gradlew build\n```\n\u003c/details\u003e\n\n\n## Releasing\n \u003cdetails\u003e\n    \u003csummary\u003eDetails\u003c/summary\u003e\n\n```console\n~$ cd typeid-kotling\n# Update version in build.gradle.kts\n~/typeid-kotlin ./gradlew updateReadmeVersion # updates the version in README.md from build.gradle.kts\n~/typeid-kotlin ./gradlew jreleaserConfig # just to double check the configuration\n~/typeid-kotlin ./gradlew clean\n~/typeid-kotlin ./gradlew publish\n~/typeid-kotlin ./gradlew jreleaserFullRelease\n```\n\u003c/details\u003e\n\n\n## Benchmarks\n\u003cdetails\u003e\n    \u003csummary\u003eDetails\u003c/summary\u003e\n\nThere is a small [JMH](https://github.com/openjdk/jmh) microbenchmark included:\n```console\n~/typeid-kotlin ./gradlew jmh\n```\n\nIn a single-threaded run, all operations perform in the range of millions of calls per second,\nwhich should be enough for most use cases \n(used setup: Eclipse Temurin 17 JDK, 2021 MacBook Pro, run on version 1.0.0).\n\n\n| Benchmark                       | Mode  | Cnt |          Score |            Error | Units |\n|---------------------------------|-------|----:|---------------:|-----------------:|-------|\n| `generate`                      | thrpt |   4 |  2.785.895,675 | ±    791.836,864 | ops/s |\n| `generate` + `toString`         | thrpt |   4 |  2.060.627,959 | ±  1.185.777,089 | ops/s |\n| `of`                            | thrpt |   4 | 20.084.528,045 | ± 3.3543.123,085 | ops/s |\n| `of` + `toString`               | thrpt |   4 |  5.853.485,485 | ±   1262.620,609 | ops/s |\n| `parse` (Error)                 | thrpt |   4 |    862.446,936 | ±     63.583,514 | ops/s |\n| `parse`  (Success)              | thrpt |   4 |  9.335.663,639 | ±    733.015,389 | ops/s |\n| `parseRaw` (Error)              | thrpt |   4 |    841.795,541 | ±    143.272,942 | ops/s |\n| `parseRaw` (Success)            | thrpt |   4 | 13.555.610,086 | ±  5.390.579,926 | ops/s |\n| `parseToValidated` (Error)      | thrpt |   4 | 20.242.071,304 | ±  2.514.786,867 | ops/s |\n| `parseToValidated` (Success)    | thrpt |   4 |  7.145.891,307 | ±  8.080.357,687 | ops/s |\n| `parseToValidatedRaw` (Error)   | thrpt |   4 | 39.712.927,570 | ±  8.692.614,496 | ops/s |\n| `parseToValidatedRaw` (Success) | thrpt |   4 | 12.377.605,683 | ±  4.873.224,352 | ops/s |\n| `toString`                      | thrpt |   4 |  9.783.700,478 | ±  2.152.238,948 | ops/s |\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleris%2Ftypeid-kotlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faleris%2Ftypeid-kotlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleris%2Ftypeid-kotlin/lists"}