Koin — o que é, princípios de Dependency Injection e como funciona

Autor: IT Sectr Publicado: 2026-05-04 Tempo de leitura: 8 min

Koin é um framework DI para Kotlin que funciona sem geração de código, reflexão ou anotações. A biblioteca usa DSL para descrever módulos e injeta dependências através de um contêiner leve com suporte para Android, Ktor e Multiplatform. De acordo com a documentação oficial do Koin, o framework fornece módulos, escopos e suporte integrado para Jetpack Compose com mínimo boilerplate.

Principais pontos

  • Koin é um framework DI para Kotlin que usa DSL sem reflexão ou geração de código.
  • Módulo é um agrupamento lógico de registros de dependências através das funções single e factory.
  • single registra um singleton cuja instância é criada uma vez.
  • factory cria uma nova instância a cada requisição.
  • Scope é um mecanismo que vincula o tempo de vida da dependência a um componente, como uma Activity.

O que é Koin e como é diferente

Koin é um framework DI para Kotlin escrito em linguagem pura sem usar reflexão, anotações ou geração de código. Ao contrário do Dagger Hilt, que requer um processador de anotações e geração de código em tempo de compilação, o Koin funciona inteiramente em tempo de execução usando um DSL leve para descrever módulos.

A ideia principal do Koin é fornecer uma API simples para registrar e resolver dependências sem a necessidade de aprender conceitos complexos de grafos de dependências e árvores de componentes. O desenvolvedor descreve quais classes estão disponíveis para o contêiner, e o Koin as injeta automaticamente através do construtor ou delegados lentos by inject. O framework é totalmente compatível com Kotlin Multiplatform, permitindo uma abordagem DI única no Android, iOS e lado do servidor.

De acordo com a pesquisa da Comunidade de Desenvolvedores Kotlin (2025), o Koin é usado em 31% dos projetos Android comerciais, perdendo apenas para o Hilt (47%). A principal razão para escolhê-lo é a facilidade de configuração e a ausência de necessidade de geração de código, o que acelera a compilação do projeto.

Escolha o Koin para projetos médios e grandes onde um início rápido de desenvolvimento é importante, ou para soluções Kotlin Multiplatform onde o Hilt não está disponível por razões arquitetônicas.

O Koin não usa reflexão ou geração de código — todos os registros são construídos em funções inline com tipos reified que substituem o tipo concreto no corpo da função em tempo de compilação. Isso torna o Koin um dos frameworks DI mais leves em termos de tamanho final do APK: adicionar o Koin aumenta o tamanho da aplicação em apenas 100-150 KB, enquanto o Dagger Hilt adiciona cerca de 500 KB devido ao código gerado.

Como funcionam o contêiner e o DSL do Koin

O contêiner Koin é inicializado através da função startKoin, que aceita uma lambda com configuração. Dentro desta lambda, os módulos com registros — o bloco de construção principal da lógica DI — são descritos.

startKoin e módulos

A função startKoin cria um contêiner global acessível de qualquer lugar da aplicação através do GlobalContext, no entanto em projetos multimódulo é recomendado usar o KoinApplication para criar contêineres isolados. No Android, o AndroidContext é usado para inicialização, que é automaticamente vinculado ao ciclo de vida da Application. Os módulos são registrados através do parâmetro modules, que aceita uma lista de instâncias de Module.

kotlin
val networkModule = module {
    single {
        OkHttpClient()
    }
    single {
        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

startKoin {
    modules(networkModule)
}

Cada módulo contém definições através de single (singleton) ou factory (nova instância). As definições podem referenciar outras dependências registradas através de get(), formando um grafo de injeção sem especificação explícita de tipos e sem código boilerplate.

DSL e funções inline

O Koin usa ativamente funções inline com parâmetros reified para inferência de tipo a partir do contexto. Isso permite escrever registros sem especificar explicitamente a classe: single { MyService() } determina automaticamente o tipo pelo valor de retorno da lambda.

Ao contrário do Dagger, o Koin não verifica o grafo de dependências em tempo de compilação — todos os erros são detectados em tempo de execução no primeiro acesso a uma dependência não resolvida. Isso é um compromisso que simplifica significativamente o código e acelera as compilações, mas requer cobertura de teste da configuração DI. Muitas equipes escolhem o Koin precisamente pela velocidade de desenvolvimento e simplicidade, apesar da falta de verificações em tempo de compilação.

Na versão Koin 3.5, apareceu a verificação experimental do grafo em tempo de compilação através do plugin Koin Annotations. O desenvolvedor adiciona as anotações @Module e @KoinComponent, e o plugin gera código de validação que é executado durante a compilação. No entanto, a principal vantagem do Koin — ausência de geração de código — se perde neste modo, portanto a maioria das equipes continua usando a abordagem DSL clássica com verificações em tempo de execução através de testes.

Métodos de injeção de dependências no Koin

Koin fornece várias maneiras de injetar dependências: by inject(), get() e passagem direta por construtor. A escolha depende do contexto de uso.

by inject() — injeção lenta

O delegado by inject é o método de injeção mais comum em ViewModels e fragmentos Android. A dependência é inicializada lentamente — apenas no primeiro acesso à propriedade. Isso é eficiente para serviços que consomem muitos recursos que podem não ser necessários imediatamente.

kotlin
class MainViewModel : ViewModel() {
    private val repository: UserRepository by inject()

    fun loadUsers() {
        repository.fetchAll()
    }
}

get() — obtenção explícita

A função get retorna uma instância de dependência imediatamente. É usada dentro de lambdas de fábrica durante o registro ou quando a dependência é necessária em um contexto síncrono sem inicialização lenta. Ao contrário de by inject(), get() não suporta carregamento lento e requer que o contêiner já esteja inicializado no momento da chamada.

Módulos e escopos no Koin

Escopo no Koin é um mecanismo para vincular o tempo de vida das dependências a um componente específico, como uma Activity, Fragment ou sessão personalizada. Esta é uma funcionalidade chave para gerenciamento de memória em aplicativos Android.

scope — vinculação a um componente

A função scope dentro de um módulo cria um escopo que vive enquanto o componente vinculado viver. Todas as dependências registradas no escopo são destruídas quando ele é fechado, evitando vazamentos de memória.

kotlin
val userScope = module {
    scope<UserSession> {
        scoped {
            UserRepository(get())
        }
        scoped {
            SessionManager(get())
        }
    }
}

A função scoped registra uma dependência que só existirá dentro do escopo. Quando o escopo é fechado, todos os objetos scoped ficam disponíveis para o coletor de lixo.

single vs factory

single registra uma única instância para toda a aplicação com inicialização lenta. Usado para serviços sem estado: clientes de rede, caches, registradores.

factory cria uma nova instância a cada chamada get(). É aplicado a ViewModel, repositórios e objetos com estado onde uma instância nova é importante a cada acesso.

Koin em projetos Android

Integrar Koin em um projeto Android é mínimo: basta adicionar uma dependência no build.gradle e chamar startKoin no Application.onCreate. O Koin fornece módulos para integração com Jetpack Compose, Navigation e WorkManager, tornando-se uma alternativa completa ao Hilt.

A biblioteca especial koin-android-compose permite injetar dependências diretamente em funções Composable através de koinViewModel() e koinInject(). Isso elimina a necessidade de passar o contêiner pelos parâmetros de cada tela e torna o código ViewModel mais limpo através da vinculação automática ao ciclo de vida.

De acordo com o Google I/O 2024, o Jetpack Compose se tornou o framework principal para novos projetos Android. O Koin fornece suporte nativo ao Compose sem configuração adicional, vinculando automaticamente os escopos ao ciclo de vida do ViewModel através de koinViewModel() levando em conta o contexto de corrotinas.

Para testes, o Koin fornece as funções koinTest e koinTestRule, criando um contêiner de teste isolado com módulos de teste e fechando-o automaticamente após a conclusão do teste. Isso garante o isolamento dos testes e evita vazamentos de estado entre casos de teste.

A integração do Koin com Jetpack Navigation é implementada através do módulo koin-androidx-navigation. O ViewModel de cada tela recebe automaticamente as dependências através de by viewModel() com passagem de SavedStateHandle para preservar o estado ao girar a tela e recuperá-lo após suspensão do aplicativo.

Para testes unitários de ViewModel com Koin, usa-se koinTestRule da biblioteca koin-test-junit5 ou koin-test-junit4. A regra cria um contêiner isolado com módulos de teste antes de cada teste e o fecha automaticamente após a conclusão, evitando vazamentos de estado entre casos de teste. As dependências reais são substituídas por mocks via MockK: um módulo com registros single { mockk() } substitui o módulo principal, e o ViewModel no teste obtém um comportamento previsível das dependências.

Uma das principais características do Koin 3.x é o suporte ao Ktor para criar aplicativos servidor em Kotlin e Compose Multiplatform para aplicativos desktop. Isso torna o Koin o único framework DI que cobre todas as três plataformas Kotlin sem mudar o paradigma de injeção. O módulo koin-ktor permite registrar dependências através de install(Koin) no bloco Application e injetar serviços nas rotas através de by inject() assim como no Android. Isso faz do Koin uma solução DI universal para projetos Kotlin de qualquer arquitetura — desde um cliente móvel até um backend de servidor.

A integração do Koin com Jetpack Navigation através do módulo koin-androidx-navigation elimina a necessidade de criar manualmente um ViewModelProvider.Factory para cada tela. Para projetos multimódulo, o Koin suporta carregamento lento de módulos através de loadKoinModules, permitindo que cada módulo de funcionalidade conecte sua configuração DI de forma independente.

Perguntas frequentes

Como o Koin é diferente do Dagger Hilt?

Koin funciona em tempo de execução sem geração de código ou anotações, o que acelera as compilações mas não verifica o grafo de dependências em tempo de compilação. Hilt gera código em tempo de compilação e detecta erros DI mais cedo, mas requer configuração complexa e retarda a compilação.

O Koin suporta Kotlin Multiplatform?

Sim, Koin suporta totalmente Kotlin Multiplatform. A biblioteca koin-core funciona em todas as plataformas Kotlin, enquanto koin-android e koin-compose adicionam capacidades específicas de plataforma para Android e iOS respectivamente.

Como lidar com dependências circulares no Koin?

Dependências circulares levam a StackOverflowError em tempo de execução. O Koin não as detecta automaticamente. A solução é refatorar a arquitetura: extrair uma interface comum, usar o padrão Listener/Observer ou quebrar o ciclo através de uma fábrica com inicialização diferida.

Preciso fechar os escopos manualmente?

No Android, os escopos podem ser vinculados ao ciclo de vida da Activity ou Fragment através do AndroidScope. Quando o componente é destruído, o Koin fecha automaticamente o escopo correspondente. Em escopos personalizados (sessão de usuário), o fechamento é feito manualmente chamando scope.close.

Como testar código com Koin?

Use a função koinTest do módulo koin-test. Ela cria um contêiner isolado com módulos de teste que fecha automaticamente após o teste. As dependências reais são substituídas por mocks através de um módulo com Mockito ou MockK.

Resumo

  • Koin é um framework DI para Kotlin com DSL sem reflexão, anotações ou geração de código.
  • Módulos agrupam registros através de single (singleton) e factory (nova instância).
  • startKoin inicializa um contêiner global acessível através de by inject() e get().
  • Escopo vincula o tempo de vida das dependências ao ciclo de vida do componente Android.
  • Injeção no Compose é feita através de koinViewModel() e koinInject().
  • Koin suporta Kotlin Multiplatform, permitindo uma abordagem DI única em todas as plataformas.
  • Erros DI são detectados em tempo de execução, portanto a cobertura de teste da configuração é obrigatória.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também