Compose 9 min read

Jetpack Compose 1.11: Pausable Composition Goes Default, and a Real Grid API Arrives

Compose 1.11.3 hit stable a couple of days ago, and unlike most point releases that quietly fix a handful of bugs, this one bundles two changes that actually shift how I think about building UI on Android. One fixes a performance ceiling that's been there since Compose launched. The other finally gives us a layout primitive that Row and Column nesting hacks have been faking for years.

Neither of these showed up with much fanfare. No keynote slot, no flashy demo. But if you ship Compose apps in production, both are worth understanding properly — one because it's free performance you get for doing nothing, the other because it changes how you'll architect screen-level layouts going forward.

1.11.3
Current stable release
Default
Pausable composition in lazy prefetch
New
Experimental Grid API

1. Pausable Composition Is Now Default — and It Closes a Real Gap

Here's the problem this solves. In classic Compose, once composition starts for a given frame, it has to run to completion before the frame can be drawn. If you're scrolling a LazyColumn and one of the upcoming items is composition-heavy — nested state reads, a moderately complex layout, maybe an image loader doing work synchronously — that composition can blow past the 16ms frame budget. The result is the thing every Compose developer has seen at least once: a stutter mid-scroll that you can't easily attribute to any single line of code.

Views never had this exact problem because measure/layout/draw on the View system don't compose UI trees the same way. It's one of the few areas where Compose genuinely lagged behind the old system, and it showed up most in feed-style UIs — exactly the kind of vertical, item-heavy lists I built for Samachar's news feed and Musist's media browser.

Pausable composition changes the contract. The runtime can now pause mid-composition if it's about to miss the frame deadline, hand control back to the system to draw the current frame, then resume exactly where it left off on the next frame. Paired with lazy layout prefetch — which already tries to compose upcoming list items ahead of time during idle frames — this means heavy items get composed incrementally across multiple frames instead of stalling a single one.

The part that matters for you: this is enabled by default as of the December '25 runtime release, carried forward into 1.11. You don't opt in, you don't change any code. If you're on a recent Compose BOM, you're already benefiting from it.

Google's own scroll benchmarks now show Compose matching View-based scroll performance for equivalent layouts — a gap that's existed since Compose 1.0 and that no amount of remember or derivedStateOf tuning fully closed on its own. If you maintain a Macrobenchmark suite (and if you've read my startup time post, you know I think you should), this is worth a fresh baseline run. I re-ran frame timing on a feed-heavy screen after bumping the BOM and saw materially fewer dropped frames during fast flings, with zero code changes on my end.

What this doesn't fix

Pausable composition smooths out composition that's structurally fine but occasionally heavy. It will not save you from a LazyColumn item that's doing actual synchronous I/O, an unbounded recomposition loop from unstable lambda captures, or a layout pass that's expensive because you nested three Boxes too many. Profile first. This raises the ceiling — it doesn't replace the floor.

2. The New Grid API — CSS Grid, Finally, for Compose

If you've ever tried to build a genuinely two-dimensional layout in Compose — a dashboard with cards spanning different row/column counts, a settings screen with mixed-size tiles, a media grid where the featured item is twice as wide as the rest — you know the pain. Row and Column give you one axis at a time. LazyVerticalGrid gets you uniform cells but falls apart the moment you need irregular spans. Most teams end up hand-rolling a custom Layout composable or reaching for a third-party library.

The new (experimental) Grid API is explicitly modeled on CSS Grid, and it shows. You define column and row tracks with fractional sizing, set a gap, then place children with explicit spans:

@OptIn(ExperimentalGridApi::class)
@Composable
fun GridExample() {
    Grid(
        config = {
            repeat(4) { column(0.25f) }
            repeat(2) { row(0.5f) }
            gap(16.dp)
        }
    ) {
        Card1(modifier = Modifier.gridItem(rowSpan = 2))
        Card2(modifier = Modifier.gridItem(columnSpan = 3))
        Card3(modifier = Modifier.gridItem(columnSpan = 2))
        Card4()
    }
}

Four equal columns, two equal rows, 16dp gaps — then Card1 spans two rows, Card2 spans three columns, Card3 spans two columns, and Card4 just takes whatever cell is left. No nested Box offsets, no manual constraint math, no guessing where the next item lands. Modifier.gridItem() handles placement; the Grid composable handles track sizing.

Where I'd actually reach for this

The API also supports reconfiguring the grid based on device state — tabletop posture on foldables, orientation changes — by recomputing the config block. That's a meaningfully better story for adaptive layouts than swapping between two separately maintained composables.

It's marked @Experimental and gated behind @OptIn(ExperimentalGridApi::class), so treat it the way you'd treat any experimental Compose API: fine for side projects and internal tools, hold off shipping it as the backbone of a production screen until it stabilizes. APIs at this stage have changed shape between releases before.

Two Smaller Additions Worth Knowing About

Riding along in the same release window are two more experimental APIs that didn't get much attention but are worth bookmarking:

Styles API brings CSS-like state-based styling to Compose components — a single declarative block where you describe the default appearance and override it for states like pressed, instead of branching with remember { mutableStateOf } and conditional modifiers:

Button(
    onClick = { /* ... */ },
    style = {
        background(Brush.linearGradient(listOf(lightPurple, lightBlue)))
        width(75.dp)
        pressed {
            background(Brush.linearGradient(listOf(Color.Magenta, Color.Red)))
        }
    }
) { Text("Login") }

MediaQuery API lets you branch layout decisions on device posture directly inside a composable — useful for the tabletop/foldable cases the Grid API also targets:

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Both are early. Neither needs action today. But the direction is consistent: Compose is borrowing well-proven patterns from CSS rather than inventing new mental models, which tends to mean a shorter learning curve once they stabilize.

Should You Upgrade Now?

Split this into two decisions. Bumping your Compose BOM to pick up pausable composition's default behavior is close to a no-brainer — it's a runtime scheduling change, not an API you opt into, and the downside risk is low. Run your existing test suite, do a sanity pass on your most scroll-heavy screens, ship it.

Building anything load-bearing on Grid, Styles, or MediaQuery today is a different call. They're real, they're usable, and the direction is clearly right — but "experimental" on a Compose API has meant breaking signature changes before final stabilization more than once. I'd prototype with Grid on an internal screen or a side project now, get comfortable with the mental model, and be ready to adopt it for production the moment it stabilizes rather than waiting for a "Compose 2.0" moment that probably won't come as a single event.

The bigger pattern across this release: Compose's performance story is converging with Views rather than asking you to trust that it eventually will, and its layout story is finally catching up to what web developers have had with CSS Grid for a decade. Neither is a flashy headline. Both are the kind of unglamorous foundation work that ends up mattering more than most feature announcements a year from now.

Comments 0

No comments yet. Be the first to leave one!

Leave a comment