Skip to main content
Version: 4.2

Koin for SDK & Libraries - Relocate your own version of Koin

Koin Embedded allows SDK and library developers to package a relocated version of Koin under a different package name, so the Koin your library uses internally cannot collide with the Koin anything else in the application uses.

There are two ways to get one: self-service, with the prebuilt artifacts or the relocation scripts, or Koin Embedded LTS, where Kotzilla builds, signs, hosts and maintains a dedicated version for you as part of Enterprise Support.

Why Use Koin Embedded?​

The Problem​

A library that uses Koin internally publishes org.koin.* as part of its dependency graph. That creates two distinct collision risks, and the second is the one that usually gets missed.

Case 1: Conflict with the host application​

The application consuming your SDK uses Koin too, on its own release schedule:

// Your SDK uses Koin 3.5.6
implementation("io.insert-koin:koin-core:3.5.6")

// Consumer app uses Koin 4.2.2
implementation("io.insert-koin:koin-core:4.2.2")
// ❌ Conflict! Gradle resolves one version for both

What this causes:

  • Gradle picks a single org.koin version for the whole app, so one of you runs against a version you never tested
  • Runtime failures from API changes between versions
  • Your SDK forces a Koin upgrade on its consumers, or blocks one

Case 2: Conflict with other SDKs alongside yours​

Your SDK is rarely the only one in the app. If another vendor's SDK also embeds Koin, you collide with each other — and neither of you controls the other's release cycle:

// The app integrates two SDKs, both using Koin internally
implementation("com.vendor-a:analytics-sdk:2.1.0") // embeds Koin 3.5.6
implementation("com.vendor-b:payments-sdk:5.0.0") // embeds Koin 4.2.2
// ❌ Same conflict, and now nobody in the chain can fix it

This is what makes a shared relocation namespace insufficient. Moving off org.koin.* onto a namespace that every embedder shares only moves the collision: two SDKs relocated to the same target conflict exactly as they did before. Avoiding this requires a namespace that is yours alone.

The Solution: Package Relocation​

Relocation rewrites Koin's packages into a different namespace and rebuilds it as a separate artifact:

// Before relocation
import org.koin.core.module.dsl.singleOf
import org.koin.core.context.startKoin

// After relocation
import acme.koin.core.module.dsl.singleOf
import acme.koin.core.context.startKoin

Two different namespaces are two different sets of classes, so they coexist with no resolution conflict:

// ✅ Your SDK bundles its own relocated Koin
implementation("io.insert-koin:acme-koin-core:3.5.6")

// ✅ Consumer app uses standard Koin
implementation("io.insert-koin:koin-core:4.2.2")
// No conflict! Two separate packages
warning

Not recommended for regular app development. Use standard Koin for your applications. Embedded Koin is for library authors — payment, analytics or authentication SDKs, shared internal libraries, third-party integrations — who need to avoid dependency conflicts.

Pre-Built Embedded Version​

Kotzilla maintains prebuilt artifacts — embedded-koin-core and embedded-koin-android — relocated to a shared embedded.koin.* namespace. Access is granted on request: contact the Koin Team.

warning

Beta, and shared-namespace — for evaluation, not for a published SDK.

Every consumer of these artifacts relocates to the same embedded.koin.* namespace, so two SDKs built on them in one application collide exactly as they would on org.koin.* — see Case 2. They are useful for trying relocation out, and for internal builds you control end to end.

To ship an SDK to third parties you need a namespace nobody else uses: relocate it yourself with the relocation scripts, or use Koin Embedded LTS.

Custom Relocation​

For a namespace that is yours alone, use the relocation scripts to rebuild Koin yourself.

warning

Beta, provided as-is. The scripts are a Beta initiative and are offered without maintenance guarantees. Everything downstream of them is your responsibility: building, verifying, publishing, and rebuilding on every future Koin release, including security fixes.

Using Relocation Scripts​

The koin-relocate project provides scripts to rebuild Koin with custom package names.

Relocation is driven by a prefix, applied to both packages and module names.

RELOCATION_PREFIX=acme   →   org.koin.*  becomes  acme.koin.*
koin-core becomes acme-koin-core

Steps:

  1. Clone the relocation scripts repository:

    git clone https://github.com/InsertKoinIO/koin-relocate.git
    cd koin-relocate
  2. Edit relocate.properties to configure the build:

    RELOCATION_PREFIX=acme
    TARGET_KOIN_VERSION=3.5.6
    KOIN_MODULES=core/koin-core;android/koin-android
    BUILD_DIR=./build
    • RELOCATION_PREFIX — the prefix applied to packages and module names
    • TARGET_KOIN_VERSION — the Koin version tag to build from
    • KOIN_MODULES — the Koin modules to relocate
    • BUILD_DIR — where the built artifacts are copied
  3. Run the relocation, which clones and rebuilds Koin from source:

    ./relocate.sh
    note

    Requires a JDK 17 environment to build the Koin project.

  4. Collect the aar/jar artifacts from BUILD_DIR. All relocated modules are also installed into your local Maven repository, so you can consume them immediately while testing.

  5. Publish them to your own Maven repository for your SDK builds to consume.

For detailed instructions, see the koin-relocate repository.

What Self-Hosting Actually Involves​

The scripts get you a first build. Running a relocated Koin as a dependency of a shipping SDK is a longer commitment, and it is worth knowing the shape of it before committing:

  • Koin's build structure. Relocation rebuilds Koin from source. You inherit its multi-module Gradle setup, its version catalogue and its toolchain requirements, and you need a JDK 17 environment that stays reproducible in CI.
  • More than package statements. Rewriting org.koin in Kotlin sources is the easy part. Resources, and declarative service files such as META-INF/services entries, also carry fully-qualified names; anything the rewrite misses fails at runtime rather than at compile time.
  • Android and multiplatform artifacts. koin-android produces aar artifacts with their own manifests and consumer rules. If you target Kotlin Multiplatform, each target publishes its own artifact with its own metadata, and the relocated coordinates have to stay consistent across all of them.
  • Publishing and signing. The scripts emit artifacts under the io.insert-koin group with a prefixed module name, installed to your local Maven repository. Publishing those to a repository you control is enough for internal use; distributing publicly means taking on the POM metadata, group ownership and signing your consumers expect, since the relocated Koin is now part of your supply chain.
  • Verifying equivalence. A relocated build has to behave exactly like the original. Koin's own test suite runs against org.koin, so you need your own assurance that resolution, scoping and lifecycle behaviour survived the rewrite — for the subset of Koin your SDK actually exercises.
  • Repeating all of it, on every Koin patch. This is the part that compounds. Every upstream release you want — including every security fix — means re-running relocation, rebuilding, re-verifying, re-signing and republishing. A relocation done once is a snapshot that ages from the day you cut it.

None of this is a reason not to self-host. It is a reason to decide deliberately, rather than discovering the cost at the third security advisory.

Koin Annotations & the Compiler Plugin​

warning

Koin Annotations and the Koin Compiler Plugin are not supported in relocated builds.

Both generate code that references org.koin directly. That generated code is produced in your project at compile time, after relocation has already happened, so it targets the standard Koin packages your relocated build no longer provides — and relocating the generated output is not part of what the scripts do.

In a relocated build, declare your modules with the Kotlin DSL (module { }, single, factory, singleOf, factoryOf) instead.

Limitations​

Beyond the Beta status and the shared-namespace caveat above, the self-service paths carry:

  • No annotations support - Koin Annotations and the compiler plugin cannot be used
  • Limited modules - Not all Koin modules relocate cleanly
  • Build complexity - Relocation means owning a build, verification and publishing pipeline
  • Maintenance overhead - Every Koin update, security fixes included, is yours to re-relocate and republish

That last one is the one that does not go away, and it is what Koin Embedded LTS exists to take off you.

Koin Embedded LTS​

Your own version of Koin LTS — conflict-free, maintained for 18 months.

Koin Embedded LTS is part of Enterprise Support by Kotzilla. Rather than handing you scripts, we build, sign, host and maintain a relocated Koin that belongs to you.

Your Own Version​

A dedicated namespace, used by you and nobody else — not a shared public one. We cut the build from a maintained Koin LTS line, relocate it into your namespace, sign it, and host it in a private repository provisioned for your organization. You add one Maven repository and depend on your own relocated modules.

You do not run relocation scripts, maintain a build pipeline, or publish the artifacts.

Conflict-Free​

Because the namespace is yours alone, your embedded Koin is invisible both to the host application and to every other SDK shipped alongside yours — whatever Koin version any of them run, and whether or not they embed Koin themselves. Neither self-service path gives you that: the prebuilt artifacts share one namespace across all their users, and a namespace you relocate yourself stays isolated only as long as you keep it patched.

18 Months​

Your build sits on a maintained LTS line — Koin 3.5.6 for Kotlin 1.x, or Koin 4.2.x for Kotlin 2.x — with a minimum of 18 months of maintenance from designation, and support continuing while your subscription is active on the version you actually ship.

Every patch on that line is rebuilt and republished into your namespace, security backports included. You consume a new version of your own artifact; you do not redo the relocation.

Scope​

Koin Embedded LTS covers koin-core and koin-android.

Onboarding includes moving you to the LTS patch level — if you are on an older version of the line today, that migration is part of getting set up, not something you do first.

info

Why LTS lines only?

Relocating an arbitrary Koin version is a one-off: it produces an artifact that exists outside any maintained line, so there is no upstream stream of fixes to rebuild from. That is precisely the artifact nobody patches — and an unpatched DI framework compiled into a widely distributed SDK is the problem this offer exists to prevent.

Building on an LTS line means there is always a next patch to relocate, for as long as your subscription runs.

Learn more about Koin Embedded LTS →

Best Practices​

SDK Development​

  1. Use embedded Koin internally - Keep it as an implementation detail
  2. Don't expose Koin types in your public API - Avoid leaking KoinComponent, Module, etc. in your SDK's public interface
  3. Initialize in isolation - Use a separate Koin instance for your SDK
  4. Pin the version - Depend on an exact relocated version, never a range
  5. Document the dependency - Mention in your SDK docs that you use Koin internally

Example: Isolated SDK Initialization​

// ✅ Good - Koin is an internal implementation detail
class PaymentSDK private constructor(context: Context) {

companion object {
private var instance: PaymentSDK? = null

fun initialize(context: Context): PaymentSDK {
return instance ?: PaymentSDK(context).also { instance = it }
}
}

private val koinApp = koinApplication {
androidContext(context)
modules(paymentModule)
}

private val paymentService: PaymentService = koinApp.koin.get()

fun processPayment(amount: Double): PaymentResult {
return paymentService.process(amount)
}
}

// ❌ Bad - Exposing Koin in public API
class PaymentSDK : KoinComponent { // Don't extend KoinComponent publicly
fun getPaymentService(): PaymentService = get() // Don't expose get()
}

Documentation​

Mention in your SDK documentation:

## Dependencies

This SDK uses Koin internally (embedded version) for dependency injection.
The embedded version is isolated and will not conflict with Koin usage
in your application.

**Internal dependency:** `io.insert-koin:acme-koin-core:3.5.6`
**Package namespace:** `acme.koin.*`

Migration Guide​

Moving an existing SDK onto a relocated Koin:

  1. Swap the dependencies — io.insert-koin:koin-core becomes your relocated coordinates, e.g. io.insert-koin:acme-koin-core.
  2. Update the imports — find import org.koin, replace with import acme.koin.
  3. Replace annotations with the DSL — if your SDK uses Koin Annotations or the compiler plugin, those declarations must be rewritten with the Kotlin DSL. See Koin Annotations & the Compiler Plugin.
  4. Test against a realistic deployment — in an app that also uses standard Koin, and alongside another SDK that embeds Koin if that is a situation your SDK will meet.

Reversing it is the same in the other direction: restore the standard koin-* coordinates and the org.koin imports.

Troubleshooting​

Build Issues​

Problem: Your relocated artifact cannot be resolved

Could not find io.insert-koin:acme-koin-core:3.5.6

Solution: Confirm the relocated artifact was actually published, and that the repository you published it to is declared in the consuming build:

repositories {
maven("https://maven.acme.com/releases") // wherever you published it
}

Runtime Issues​

Problem: ClassNotFoundException at runtime

Solution: Verify you're using the relocated package names everywhere:

// Wrong
import org.koin.core.context.startKoin

// Correct
import acme.koin.core.context.startKoin

If the missing class is only referenced from a resource or a META-INF/services entry, the relocation missed a non-source reference — check those files carry the relocated names too.

Dependency Conflicts​

Problem: Still seeing version conflicts

Solution: Ensure you're not mixing standard and relocated Koin in the same module:

// ❌ Don't mix
implementation("io.insert-koin:koin-core:3.5.6") // Standard
implementation("io.insert-koin:acme-koin-core:3.5.6") // Relocated

// ✅ Use only your relocated build
implementation("io.insert-koin:acme-koin-core:3.5.6")

Problem: Conflict with another SDK that also embeds Koin

Solution: You are both relocated to the same namespace — most likely both using the prebuilt embedded.koin.* artifacts. One of you needs a namespace of your own: relocate it yourself, or use Koin Embedded LTS.

Feedback & Support​

For the self-service paths — prebuilt artifacts and relocation scripts — we value your feedback:

See Also​