{"id":37019244,"url":"https://github.com/timortel/grpc-kotlin-multiplatform","last_synced_at":"2026-03-08T00:01:42.685Z","repository":{"id":37233264,"uuid":"503391702","full_name":"TimOrtel/GRPC-Kotlin-Multiplatform","owner":"TimOrtel","description":"Gradle Plugin and Library to use gRPC within Kotlin multiplatform code.","archived":false,"fork":false,"pushed_at":"2026-03-07T13:07:42.000Z","size":2012,"stargazers_count":127,"open_issues_count":6,"forks_count":23,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-03-07T16:48:53.585Z","etag":null,"topics":["grpc","kotlin-multiplatform","protocol-buffers"],"latest_commit_sha":null,"homepage":"","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/TimOrtel.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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-06-14T14:21:05.000Z","updated_at":"2026-03-07T13:07:23.000Z","dependencies_parsed_at":"2026-03-08T00:01:11.785Z","dependency_job_id":null,"html_url":"https://github.com/TimOrtel/GRPC-Kotlin-Multiplatform","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/TimOrtel/GRPC-Kotlin-Multiplatform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOrtel%2FGRPC-Kotlin-Multiplatform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOrtel%2FGRPC-Kotlin-Multiplatform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOrtel%2FGRPC-Kotlin-Multiplatform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOrtel%2FGRPC-Kotlin-Multiplatform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TimOrtel","download_url":"https://codeload.github.com/TimOrtel/GRPC-Kotlin-Multiplatform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TimOrtel%2FGRPC-Kotlin-Multiplatform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30238079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T23:52:25.683Z","status":"ssl_error","status_checked_at":"2026-03-07T23:52:25.373Z","response_time":53,"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":["grpc","kotlin-multiplatform","protocol-buffers"],"created_at":"2026-01-14T02:04:20.335Z","updated_at":"2026-03-08T00:01:42.672Z","avatar_url":"https://github.com/TimOrtel.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)\n[![Download](https://img.shields.io/maven-central/v/io.github.timortel/kmp-grpc-core) ](https://central.sonatype.com/artifact/io.github.timortel/kmp-grpc-core)\n![version](https://img.shields.io/badge/version-2.0.0-blue)\n\n![badge][badge-android]\n![badge][badge-jvm]\n![badge][badge-js]\n![badge][badge-wasmjs]\n![badge][badge-ios]\n\n# gRPC Kotlin Multiplatform\nThis projects implements client-side gRPC for Android, JVM, Native (including iOS), JavaScript and WASM.\n\n## Table of contents\n- [Features](#features)\n- [Usage](#usage)\n- [Setup](#setup)\n- [Example Implementation](#example-implementation)\n- [Contributing](#contributing)\n- [Implementation details](#implementation-details)\n- [License](#license)\n\n## Features\n### Supported rpc types:\n|                    | JVM/Android | Native (including iOS) | JavaScript (Browser + NodeJs)) | WasmJs (Browser + NodeJs)) |\n|--------------------|-------------|------------------------|--------------------------------|----------------------------|\n| `Unary`            | ✅           | ✅                      | ✅                              | ✅                          |\n| `Client-streaming` | ✅           | ✅                      | ❌                              | ❌                          |\n| `Server-streaming` | ✅           | ✅                      | ✅                              | ✅                          |\n| `Bidi-streaming`   | ✅           | ✅                      | ❌                              | ❌                          |\n\n### Supported protobuf versions\n|               | Support status |\n|---------------|----------------|\n| Proto2        | ✅ Supported    |\n| Proto3        | ✅ Supported    |\n| Editions 2023 | ✅ Supported    |\n| Editions 2024 | ✅ Supported    |\n\nPlease note that not all features may be available even if the protobuf version is marked as _supported_.\n\n### Supported proto types:\n| Proto Type   | Kotlin Type  |\n|-------------|-------------|\n| `double`    | `Double`    |\n| `float`     | `Float`     |\n| `int32`     | `Int`       |\n| `int64`     | `Long`      |\n| `uint32`    | `UInt`      |\n| `uint64`    | `ULong`     |\n| `sint32`    | `Int`       |\n| `sint64`    | `Long`      |\n| `fixed32`   | `UInt`      |\n| `fixed64`   | `ULong`     |\n| `sfixed32`  | `Int`       |\n| `sfixed64`  | `Long`      |\n| `bool`      | `Boolean`   |\n| `string`    | `String`    |\n| `bytes`     | `ByteArray` |\n\n### Supported proto options and features:\n\n### Legacy options\n| Proto Option           | Proto2 | Proto3 | Edition 2023 |\n|------------------------|--------|--------|--------------|\n| `java_package`         | ✅      | ✅      | ✅            | \n| `java_outer_classname` | ✅      | ✅      | ✅            | \n| `java_multiple_files`  | ✅      | ✅      | ✅            | \n| `deprecated`           | ✅      | ✅      | ✅            | \n| `packed`               | ✅      | ✅      | ✅            | \n| `default` enum-option  | ✅      | ✅      | ✅            | \n| `optimize_for`         | ❌      | ❌      | ❌            |\n\n### Features\n| Feature                        | Edition 2023 | Edition 2024 |\n|--------------------------------|--------------|--------------|\n| `field_presence`               | ✅            | ✅            |\n| `repeated_field_encoding`      | ✅            | ✅            |\n| `enum_type`                    | ✅            | ✅            |\n| `json_format`                  | ⏳ Planned    | ⏳ Planned    |\n| `message_encoding`             | ⏳ Planned    | ⏳ Planned    |\n| `utf8_validation`              | ❌            | ❌            |\n| `default_symbol_visibility`    |              | ✅            |\n| `(pb.java).nest_in_file_class` |              | ✅            |\n| `enforce_naming_style`         |              | ⏳ Planned    |\n\n\n\n### Code generation:\n| Proto Struct | Support Status |\n|--------------|---------------|\n| Messages     | ✅ Supported  |\n| Enums        | ✅ Supported  |\n| Services     | ✅ Supported  |\n\n### Well-known types:\nFor reference, see [the official documentation](https://protobuf.dev/reference/protobuf/google.protobuf/). Well-known types support must be enabled in your gradle config (see [Setup](#setup)). \n\n| Protobuf Type          | Supported     |\n|------------------------|---------------|\n| `any.proto`            | ✅ Supported   |\n| `api.proto`            | ✅ Supported   |\n| `descriptor.proto`     | ✅ Supported   |\n| `duration.proto`       | ✅ Supported   |\n| `empty.proto`          | ✅ Supported   |\n| `field_mask.proto`     | ✅ Supported   |\n| `source_context.proto` | ✅ Supported   |\n| `struct.proto`         | ✅ Supported   |\n| `timestamp.proto`      | ✅ Supported   |\n| `type.proto`           | ✅ Supported   |\n| `wrappers.proto`       | ✅ Supported   |\n\n### Additional Features\n- ✅ Generates DSL syntax to create messages\n\n## Usage\nThis plugin generates a kotlin class for each message/enum defined in the proto files. Assume you have the following proto file:\n```protobuf\nsyntax = \"proto3\";\n\npackage com.example;\n\noption java_multiple_files = true;\n\nmessage HelloRequest {\n  string greeting = 1;\n}\n\nmessage HelloResponse {\n  string response = 1;\n}\n\nservice HelloService {\n  rpc sayHello (HelloRequest) returns (HelloResponse);\n\n  rpc sayHelloMultipleTimes (HelloRequest) returns (stream HelloResponse);\n}\n```\n\n### Creating proto objects\nIn your common module, you can create proto objects like this:\n```kotlin\nval request = helloRequest {\n    greeting = \"My greeting\"\n}\n```\n\n### Making rpc calls\nThe request syntax is very similar to the one provided by gRPC Java. Add this code to your common module:\n```kotlin\n suspend fun makeCall(): String {\n    val channel = Channel.Builder()\n        .forAddress(\"localhost\", 8082) // replace with your address and your port\n        .usePlaintext() // To force grpc to allow plaintext traffic, if you don't call this https is used.\n        .build()\n    \n    // For each service a unique class is generated.\n    val stub = HelloServiceStub(channel)\n\n    val request = helloRequest {\n        greeting = \"My greeting\"\n    }\n     \n     return try {\n         val response: HelloResponse = stub\n             .withDeadlineAfter(10, TimeUnit.SECONDS) // Specify a deadline if you need to\n             .myRpc(request)\n\n         //Handle response\n         response.response\n     } catch (e: StatusException) {\n         \"An exception occurred: $e\"\n     }\n}\n```\n\n### KeepAlive Configuration\nYou can configure keep-alive to maintain active connections and detect broken connections:\n\n```kotlin\nval channel = Channel.Builder()\n    .forAddress(/*...*/)\n    .withKeepAliveConfig(\n        // Exemplary configuration\n        KeepAliveConfig.Enabled(\n            time = 30.seconds,           // Send keepalive ping every 30 seconds\n            timeout = 10.seconds,         // Wait 10 seconds for ping response\n            withoutCalls = true          // Send keepalive even when no RPCs are active\n        )\n    )\n    .build()\n```\n\nThe keep-alive configuration has no effect on JS/WasmJs. \n\n### Trusted Certificates Configuration\n\nBy default, on JVM targets the default device certificates are trusted. On Native targets, all certificates from [webpki-roots](https://github.com/rustls/webpki-roots) are trusted.\nFurthermore, you can provide additional certificates that the channel should trust when establishing TLS connections.\nBoth CA certificates and leaf/self-signed certificates are accepted:\n\n```kotlin\nval channel = Channel.Builder()\n    .forAddress(/*...*/)\n    .withTrustedCertificates(\n        listOf(\n            Certificate.fromPem(/* PEM string */),\n            Certificate.fromPem(/* another PEM */)\n        )\n    )\n    .build()\n```\n\nIf only the certificates added using `withTrustedCertificates` should be trusted, call `trustOnlyProvidedCertificates`:\n```kotlin\nval channel = Channel.Builder()\n    .forAddress(/*...*/)\n    .withTrustedCertificates(/*...*/)\n    .trustOnlyProvidedCertificates()\n    .build()\n```\n\nThe trusted certificate configuration has no effect on JS/WasmJs.\n\n### Client Identity Configuration\n\nThe `withClientIdentity` function allows the client to present its own certificate and private key during the TLS handshake.\nThis identity pair is used by the server to authenticate the client before allowing requests.\n\nYou can configure the channel to use a client identity as follows:\n\n```kotlin\nval channel = Channel.Builder()\n    .forAddress(/*...*/)\n    .withClientIdentity(\n        certificate = Certificate.fromPem(/* client certificate PEM */),\n        key = PrivateKey.fromPem(/* private key PEM */)\n    )\n    .build()\n```\n\nThe client identity configuration has no effect on JS/WasmJs.\n\n### Working with well known types\n\n#### `Any` Message Extensions\n\n##### Example: `wrap`\nWraps a message inside an `Any` message.\n```kotlin\nval myMessage = myMessage {} // Some message\nval wrapped = Any.wrap(myMessage)\n```\n\n##### Example: `unwrap`\nExtracts a message from an `Any` object.\n```kotlin\nval extractedMessage: MyMessage = wrapped.unwrap(MyMessage.Companion)\n```\n\n##### Example: `isType`\nChecks if an `Any` object holds a specific message type.\n```kotlin\nif (wrapped.isType(MyMessage.Companion)) {\n    println(\"The message is of type MyMessage\")\n}\n```\n\n#### `Duration` Extensions\n\n##### Example: `ofSeconds`\nCreates a `Duration` from seconds.\n```kotlin\nval duration = Duration.ofSeconds(120)\n```\n\n##### Example: `ofMillis`\nCreates a `Duration` from milliseconds.\n```kotlin\nval duration = Duration.ofMillis(500)\n```\n\n##### Example: `fromDuration`\nCreates a `Duration` from `kotlin.time.Duration`.\n```kotlin\nval duration = Duration.fromDuration(1.5.seconds)\n```\n\n##### Example: `toDuration`\nConverts a `Duration` to `kotlin.time.Duration`.\n```kotlin\nval kotlinDuration: kotlin.time.Duration = duration.toDuration()\n```\n\n#### `Timestamp` Extensions\n\n##### Example: `fromInstant`\nCreates a `Timestamp` from `Instant`.\n```kotlin\nval timestamp = Timestamp.fromInstant(Instant.now())\n```\n\n##### Example: `toInstant`\nConverts a `Timestamp` to `Instant`.\n```kotlin\nval instant: Instant = timestamp.toInstant()\n```\n\n### Unknown Fields Support\nUnknown fields are automatically captured when parsing messages and also serialized back to the wire. \nYou can access them using the generated property:\n```kotlin\nclass ExampleMessage {\n    val unknownFields: List\u003cUnknownField\u003e\n}\n```\n\n### Intercepting Calls\nYou can intercept calls to modify what is sent to the server and received from the server. Example:\n```kotlin\nval loggingInterceptor = object : CallInterceptor {\n    override fun onStart(methodDescriptor: MethodDescriptor, metadata: Metadata): Metadata {\n        println(\"Call started ${methodDescriptor.fullMethodName}\")\n        return super.onStart(methodDescriptor, metadata)\n    }\n\n    override fun onClose(\n        methodDescriptor: MethodDescriptor,\n        status: Status,\n        trailers: Metadata\n    ): Pair\u003cStatus, Metadata\u003e {\n        println(\"Call closed ${methodDescriptor.fullMethodName}\")\n        return super.onClose(methodDescriptor, status, trailers)\n    }\n}\n\nval channel = Channel.Builder\n    .forAddress(\"localhost\", 8080)\n    .withInterceptors(loggingInterceptor)\n    .build()\n```\n\n### Using extensions\n**Forward declarations are currently not supported.**\n\nProto editions support [extensions](https://protobuf.dev/programming-guides/editions/#extensions). Extension fields are not generated\nas part of the message itself, but must instead be set indirectly on the `extensions` property.\n\nAs an example, consider the following proto file:\n```protobuf\n// sample.proto\n\nedition = \"2023\";\n\nmessage MyMessage {\n  string regularField = 1;\n  extensions 2 to 5;\n}\n\nextend MyMessage {\n  string myExtension = 2;\n}\n```\n\nYou can construct a message of type `MyMessage` like this:\n```kotlin\nval msg = Sample.MyMessage(\n    regularField = \"val1\", \n    extensions = buildExtensions {\n        set(Sample.myExtension, \"val2\")\n    }\n)\n```\n\nThe values from extensions can be read from a message like this:\n```kotlin\nval msg: Sample.MyMessage = // ...\nval value = msg.extensions[Sample.myExtension]\n```\n\nWhen deserializing a message received from the server, all known extensions for the message type are considered.\n\n## Setup\nIn your top-level build.gradle.kts, add the following:\n```kotlin\nbuildscript {\n    repositories {\n        //...\n        gradlePluginPortal()\n    }\n\n    // ...\n}\n```\n\n### Common Module build.gradle.kts\nAdd the following to your plugins block:\n```kotlin\nplugins {\n    kotlin(\"multiplatform\")\n\n    //...\n    id(\"io.github.timortel.kmpgrpc.plugin\") version \"\u003clatest version\u003e\"\n}\n```\n\nAdd the library as a dependency:\n```kotlin\nrepositories {\n    // ...\n    mavenCentral()\n}\n\nkotlin {\n    // Required\n    applyDefaultHierarchyTemplate()\n    \n    // ...\n}\n\nkmpGrpc {\n    // declare the targets you need.\n    common() // required\n    jvm()\n    android()\n    js()\n    native() // for native targets like iOS\n\n    // Optional: if the protobuf well known types should be included\n    // https://protobuf.dev/reference/protobuf/google.protobuf/\n    includeWellKnownTypes = true\n    \n    // Optional: if all generated source files should have 'internal' visibility.\n    internalVisibility = true\n\n    /*\n     * Defines the naming convention for generated classes and properties.\n     * * - [NamingStrategy.KOTLIN_IDIOMATIC] (Default): Transforms names to match Kotlin \n     * conventions (e.g., snake_case fields become camelCase, messages become PascalCase).\n     * Repeated fields are automatically suffixed with \"List\".\n     * * - [NamingStrategy.PROTO_LITERAL]: Keeps names exactly as they are defined \n     * in the .proto source files.\n     * * - [NamingStrategy.LEGACY]: Matches the behavior of major version 1 of this library. Keeps the \n     * original .proto names but appends \"List\" and \"Map\" suffixes where applicable.\n     */\n    namingStrategy = NamingStrategy.KOTLIN_IDIOMATIC\n    \n    // Specify the folders where your proto files are located, you can list multiple.\n    protoSourceFolders = project.files(\"\u003csource to your protos\u003e\")\n}\n```\n\n## Example Implementation\nSee an example implementation of an Android app and an iOS app in the `examples` folder.\n\n## Building locally\nTo build the native targets locally, you will need to have rust installed on your local machine. Once setup, you can run the following Gradle commands:\n1. To build the library `gradle kmp-grpc-core:publishToMavenLocal`\n2. To build the plugin `gradle kmp-grpc-plugin:publishToMavenLocal`\n\nBy default, kmp-grpc-core prints trace logs. To deactivate, build the library with `-Pio.github.timortel.kmp-grpc.internal.native.release=true`.\n\n## Contributing\nFeel free to implement improvements, bug fixes and features and create a pull request.\n\n## Implementation details\n\n### How does it work internally?\nThe plugin generates kotlin code for all provided proto files. No `protoc` is needed. The networking code is handled\nby gRPC for JVM and by [tonic](https://github.com/hyperium/tonic) for all native targets. For JavaScript, the requests are handled by [ktor](https://github.com/ktorio/ktor).\n\n## License\nCopyright 2026 Tim Ortel\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n\n\n[badge-android]: http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat\n[badge-ios]: http://img.shields.io/badge/platform-ios-CDCDCD.svg?style=flat\n[badge-js]: http://img.shields.io/badge/platform-js-F8DB5D.svg?style=flat\n[badge-wasmjs]: http://img.shields.io/badge/platform-wasmjs-F8DB5D.svg?style=flat\n[badge-jvm]: http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimortel%2Fgrpc-kotlin-multiplatform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimortel%2Fgrpc-kotlin-multiplatform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimortel%2Fgrpc-kotlin-multiplatform/lists"}