Connect with us


Kamel – Kotlin asynchronous media loading and caching library for Compose

Kamel is an asynchronous media loading library for Compose Multiplatform. It provides a simple, customizable and efficient way to load, cache, decode and display images in your application. By default, it uses Ktor client for loading resources.

Kamel Setup

Kamel is published on Maven Central:

repositories {
    // ...


Add the dependency to the common source-set:

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                // ...


Add the dependency to the dependencies block:

dependencies {
    // ...

Ktor HttpClient Engine

Make sure to add a dependency for Ktor HttpClient engine for your platforms using this link.

Kamel Usage

Loading an image resource

To load an image asynchronously, you can use lazyPainterResource composable, it can load images from different data sources:

// String
lazyPainterResource(data = "")

// Ktor Url
lazyPainterResource(data = Url(""))

// URI
lazyPainterResource(data = URI(""))

// File (JVM, Native)
lazyPainterResource(data = File("/path/to/image.png"))

// File (JS)
lazyPainterResource(data = File(org.w3c.files.File(arrayOf(blob), "/path/to/image.png")))

// URL
lazyPainterResource(data = URL(""))

// and more...

lazyPainterResource can be used to load SVG, XML, JPEG, and PNG by default depending on the platform implementation.

lazyPainterResource returns a Resource<Painter> object which can be used to display the image using KamelImage composable.

Platform specific implementations

Since there isn’t any shared resource system between Android and Desktop, some implementations (e.g. fetchers and mappers) are only available for a specific platform:

Desktop only implementations

To load an image file from desktop application resources, you have to add resourcesFetcher to the KamelConfig:

val desktopConfig = KamelConfig {
    // Available only on Desktop.

Assuming there’s an image.png file in the /resources directory in the project:

CompositionLocalProvider(LocalKamelConfig provides desktopConfig) {

Android only implementations

To load an image file from android application resources, you have to add resourcesFetcher and resourcesIdMapper to the KamelConfig:

val context: Context = LocalContext.current

val androidConfig = KamelConfig {
    // Available only on Android.
    // Available only on Android.

Assuming there’s an image.png file in the /res/raw directory in the project:

CompositionLocalProvider(LocalKamelConfig provides androidConfig) {

Configuring an image resource

lazyPainterResource supports configuration using a trailing lambda:

val painterResource: Resource<Painter> = lazyPainterResource("") {

    // CoroutineContext to be used while loading the image.
    coroutineContext = Job() + Dispatcher.IO

    // Customizes HTTP request
    requestBuilder { // this: HttpRequestBuilder
        header("Key", "Value")
        parameter("Key", "Value")


Displaying an image resource

KamelImage is a composable function that takes a Resource<Painter> object, display it and provide extra functionality:

    resource = painterResource,
    contentDescription = "Profile",

KamelImage can also be used to get the exception using onFailure, and progress using onLoading parameters, to display a snackbar or a progress indicator, depending on the case:

val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Box {
        resource = painterResource,
        contentDescription = "Profile",
        onLoading = { progress -> CircularProgressIndicator(progress) },
        onFailure = { exception ->
            coroutineScope.launch {
                    message = exception.message.toString(),
                    actionLabel = "Hide",
                    duration = SnackbarDuration.Short
    SnackbarHost(hostState = snackbarHostState, modifier = Modifier.padding(16.dp))

You can also provide your own custom implementation using a simple when expression:

when (val resource = lazyPainterResource("")) {
    is Resource.Loading -> {
    is Resource.Success -> {
        val painter: Painter = resource.value
        Image(painter, contentDescription = "Profile")
    is Resource.Failure -> {
        val fallbackPainter = painterResource("/path/to/fallbackImage.jpg")
        Image(fallbackPainter, contentDescription = "Profile")

Crossfade animation

You can enable, disable or customize crossfade (fade-in) animation through the animationSpec parameter. Setting animationSpec to null will disable the animation:

    resource = imageResource,
    contentDescription = "Profile",
    // null by default
    animationSpec = tween(),

Configuring Kamel

The default implementation is KamelConfig.Default. If you wish to configure it, you can do it the following way:

val customKamelConfig = KamelConfig {
    // Copies the default implementation if needed

    // Sets the number of images to cache
    imageBitmapCacheSize = DefaultCacheSize

    // adds an ImageBitmapDecoder

    // adds a FileFetcher

    // Configures Ktor HttpClient
    httpFetcher {
        defaultRequest {
            cacheControl(CacheControl.MaxAge(maxAgeSeconds = 10000))

        install(HttpRequestRetry) {
            maxRetries = 3
            retryIf { httpRequest, httpResponse ->
        // Requires adding "io.ktor:ktor-client-logging:$ktor_version"
        Logging {
            level = LogLevel.INFO
            logger = Logger.SIMPLE

    // more functionality available.

Cache size (number of entries to cache)

Kamel provides a generic Cache<K,V> interface, the default implementation uses LRU memory cache mechanism backed by LinkedHashMap. You can provide a number of entries to cache for each type like so:

KamelConfig {
    // 100 by default
    imageBitmapCacheSize = 500
    // 100 by default
    imageVectorCacheSize = 300
    // 100 by default
    svgCacheSize = 200

Applying Kamel configuration

You can use LocalKamelConfig to apply your custom configuration:

CompositionLocalProvider(LocalKamelConfig provides customKamelConfig) {


Contributions are always welcome!. If you’d like to contribute, please feel free to create a PR or open an issue.

Kamel on GitHub:
Platform: Android
⭐️: 220