
Build plugin publishing native libraries as NuGet packages, auto-generating C# bindings and reverse bindings, shipping a fixed-ABI runtime, and providing a configurable bind DSL.
A plugin that allows you to publish your Kotlin/Native libraries as NuGet packages to be consumed by .NET projects.
https://www.youtube.com/watch?v=DywUS-qYn6o
Read the announcement: Bring your KMP library to NuGet
Alpha. Kotlin to C# can still break in a 0.x release; the release notes say how to migrate. C# to Kotlin is experimental, behind @ExperimentalNugetBindingApi.
[!WARNING] The generated bindings are your package's public API, so a plugin bump can break your consumers. Pin the plugin and diff
Interop.cson every bump.
// build.gradle.kts
plugins {
kotlin("multiplatform")
id("io.github.xxfast.kotlin.native.nuget") version "<version>"
}
kotlin {
mingwX64 { binaries { sharedLib() } }
macosArm64 { binaries { sharedLib() } }
}
nuget {
publish {
packageId = "MyCatLib"
version = "1.0.0"
authors = "yourname"
description = "My Kotlin/Native library"
rootPackage = "com.example.cats"
}
}[!NOTE] The plugin adds
nuget-runtimeandnuget-annotationsfor you; nothing to declare.
// Kotlin
interface Pet { val name: String; fun speak(): String }
enum class Mood { HAPPY, SLEEPY, GRUMPY }
abstract class Animal(override val name: String) : Pet
class Cat(name: String, val lives: Int = 9) : Animal(name) {
var brother: Cat? = null
var mood: Mood = Mood.SLEEPY
val toys: List<Toy> = listOf(Toy("Mouse", "Gray"))
val onMeow: () -> String = { "Meow! My name is $name" }
override fun speak(): String = "Meow!"
}
data class Toy(val name: String, val color: String)
class Box<T>(val item: T)
fun owner(name: String): String? = if (name == "Oreo") "Isuru" else null// C# (auto-generated)
using var oreo = new Cat("Oreo", 9);
oreo.Name; // "Oreo"
oreo.Speak(); // "Meow!"
oreo.Brother = new Cat("Mylo", 9); // nullable object setter
oreo.Mood = Mood.Happy; // enums
using var toy = new Toy("Mouse", "Gray");
toy.ToString(); // "Toy(name=Mouse, color=Gray)"
toy.Equals(toy.Copy("Ball", "Red")); // data class equality + copy
IReadOnlyList<Toy> toys = oreo.Toys; // collections
using var box = new Box<string>("hello"); // generics
string? owner = CatKt.Owner("Oreo"); // nullable returns
using var onMeow = oreo.OnMeow;
onMeow.Invoke(); // lambdas
IPet pet = oreo; // interface polymorphism
Animal animal = oreo; // abstract class hierarchy[!TIP] Everything public in the module is bridged, not just
rootPackage. Scope it withpublish { include(...); exclude(...) }.
[!IMPORTANT] Not everything bridges. Unsupported declarations are skipped with a named diagnostic. See Publishing Kotlin to C# for the limits.
public class Template
{
public Template(string template) { ... } // constructor
public string Name { get; set; } // instance property
public string Apply(string name) { ... } // instance method
public static Template Parse(string template) { ... } // static method
public void Use(Action<Template> action) { ... } // IDisposable pattern
public static string Render(Template template, string name) { ... } // static method
} // build.gradle.kts
nuget {
dependencies {
dependency("TestDependency", version = "1.0.0") {
bind {
includeNamespaces("Test.Text") // C# namespaces to bind
alias("Test.Text", "sample.text") // C# namespace to Kotlin package
}
}
}
}// Kotlin (auto-generated)
val template = Template("Hello, {name}") // constructor
template.name = "Oreo" // instance property
template.apply("Oreo") // instance method
Template.parse("Hello, {name}") // static -> companion object
template.use { Template.render(it, "Oreo") } // handles are AutoCloseableFull docs: xxfast.github.io/kotlin-native-nuget
bind {} DSL and what binds todaynuget {} DSL reference
[!TIP] See the architecture overview for how the bridge is built, ROADMAP.md for what's next, and docs/adr/ for the architecture decision records.
A plugin that allows you to publish your Kotlin/Native libraries as NuGet packages to be consumed by .NET projects.
https://www.youtube.com/watch?v=DywUS-qYn6o
Read the announcement: Bring your KMP library to NuGet
Alpha. Kotlin to C# can still break in a 0.x release; the release notes say how to migrate. C# to Kotlin is experimental, behind @ExperimentalNugetBindingApi.
[!WARNING] The generated bindings are your package's public API, so a plugin bump can break your consumers. Pin the plugin and diff
Interop.cson every bump.
// build.gradle.kts
plugins {
kotlin("multiplatform")
id("io.github.xxfast.kotlin.native.nuget") version "<version>"
}
kotlin {
mingwX64 { binaries { sharedLib() } }
macosArm64 { binaries { sharedLib() } }
}
nuget {
publish {
packageId = "MyCatLib"
version = "1.0.0"
authors = "yourname"
description = "My Kotlin/Native library"
rootPackage = "com.example.cats"
}
}[!NOTE] The plugin adds
nuget-runtimeandnuget-annotationsfor you; nothing to declare.
// Kotlin
interface Pet { val name: String; fun speak(): String }
enum class Mood { HAPPY, SLEEPY, GRUMPY }
abstract class Animal(override val name: String) : Pet
class Cat(name: String, val lives: Int = 9) : Animal(name) {
var brother: Cat? = null
var mood: Mood = Mood.SLEEPY
val toys: List<Toy> = listOf(Toy("Mouse", "Gray"))
val onMeow: () -> String = { "Meow! My name is $name" }
override fun speak(): String = "Meow!"
}
data class Toy(val name: String, val color: String)
class Box<T>(val item: T)
fun owner(name: String): String? = if (name == "Oreo") "Isuru" else null// C# (auto-generated)
using var oreo = new Cat("Oreo", 9);
oreo.Name; // "Oreo"
oreo.Speak(); // "Meow!"
oreo.Brother = new Cat("Mylo", 9); // nullable object setter
oreo.Mood = Mood.Happy; // enums
using var toy = new Toy("Mouse", "Gray");
toy.ToString(); // "Toy(name=Mouse, color=Gray)"
toy.Equals(toy.Copy("Ball", "Red")); // data class equality + copy
IReadOnlyList<Toy> toys = oreo.Toys; // collections
using var box = new Box<string>("hello"); // generics
string? owner = CatKt.Owner("Oreo"); // nullable returns
using var onMeow = oreo.OnMeow;
onMeow.Invoke(); // lambdas
IPet pet = oreo; // interface polymorphism
Animal animal = oreo; // abstract class hierarchy[!TIP] Everything public in the module is bridged, not just
rootPackage. Scope it withpublish { include(...); exclude(...) }.
[!IMPORTANT] Not everything bridges. Unsupported declarations are skipped with a named diagnostic. See Publishing Kotlin to C# for the limits.
public class Template
{
public Template(string template) { ... } // constructor
public string Name { get; set; } // instance property
public string Apply(string name) { ... } // instance method
public static Template Parse(string template) { ... } // static method
public void Use(Action<Template> action) { ... } // IDisposable pattern
public static string Render(Template template, string name) { ... } // static method
} // build.gradle.kts
nuget {
dependencies {
dependency("TestDependency", version = "1.0.0") {
bind {
includeNamespaces("Test.Text") // C# namespaces to bind
alias("Test.Text", "sample.text") // C# namespace to Kotlin package
}
}
}
}// Kotlin (auto-generated)
val template = Template("Hello, {name}") // constructor
template.name = "Oreo" // instance property
template.apply("Oreo") // instance method
Template.parse("Hello, {name}") // static -> companion object
template.use { Template.render(it, "Oreo") } // handles are AutoCloseableFull docs: xxfast.github.io/kotlin-native-nuget
bind {} DSL and what binds todaynuget {} DSL reference
[!TIP] See the architecture overview for how the bridge is built, ROADMAP.md for what's next, and docs/adr/ for the architecture decision records.