Skip to content

Coil

UI & GraphicsGraphics / Image ProcessingKotlin

What it is

Coil is an image loading library for Android and Compose Multiplatform, built on coroutines with automatic memory and disk caching.

AsyncImage loads and displays in one composable, handling cancellation when the item scrolls off screen. Caching is on by default.

Installation

implementation("io.coil-kt.coil3:coil-compose:3.0.0")

Getting started

The smallest useful thing you can do with it, and what each part means.

Loading in Compose
AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
        .data(book.coverUrl)
        .crossfade(true)
        .memoryCacheKey(book.id.toString())
        .build(),
    contentDescription = book.title,   // required for accessibility
    placeholder = painterResource(R.drawable.placeholder),
    error = painterResource(R.drawable.broken),
    contentScale = ContentScale.Crop,
    modifier = Modifier.size(120.dp).clip(RoundedCornerShape(8.dp)),
)
Requests are cancelled automatically when the composable leaves composition, which is what keeps a fast-scrolling list from queuing hundreds of abandoned downloads.

Advanced usage

Where the library earns its place over a simpler alternative.

Custom loader and transformations
val imageLoader = ImageLoader.Builder(context)
    .memoryCache {
        MemoryCache.Builder().maxSizePercent(context, 0.25).build()
    }
    .diskCache {
        DiskCache.Builder()
            .directory(context.cacheDir.resolve("image_cache"))
            .maxSizeBytes(100L * 1024 * 1024)
            .build()
    }
    .crossfade(true)
    .build()

AsyncImage(
    model = ImageRequest.Builder(context)
        .data(url)
        .transformations(CircleCropTransformation())
        .size(200, 200)      // decode at display size, not full resolution
        .build(),
    imageLoader = imageLoader,
    contentDescription = null,
)
Setting an explicit size is the single most effective memory optimisation — decoding a 4000-pixel photo to display it at 200 pixels wastes about 60 MB per image.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Images never appear
The network fetcher is not on the classpath in Coil 3 — add coil-network-okhttp, which is a separate artifact.
OutOfMemoryError while scrolling
Full-resolution decoding. Set size() on the request and cap the memory cache percentage.

Best practices

  • Always set contentDescription, or null explicitly for decorative images.
  • Specify a target size so images are not decoded at full resolution.
  • Create one ImageLoader for the application; a new one per screen loses the cache.
  • Set a memoryCacheKey when the same image appears under different URLs.

Background

Why it exists, and what it was reacting to.

Coil (Coroutine Image Loader) was written in Kotlin with coroutines from the start, making it smaller and better integrated than the older Java-based Glide and Picasso.