
When we build UI’s using Jetpack Compose, we write elegant, declarative code like:

But what actually happens under the hood when this code is compiled?
Is it just calling Text() during every recomposition? Not quite.
- The truth is, Jetpack Compose uses a powerful compiler plugin that rewrites your
@Composablefunctions into a lower-level form optimized for performance. This transformation is what makes smart recomposition, slot management, and state skipping possible.
In this blog, we’ll peel back the layers and see:
- How the Compose compiler transforms your Composables.
- What the
Composerandchangedflags are - How recomposition is skipped using bitmasks
- What “groups” and “slot tables” mean in Compose
How the Compose compiler transforms your Composables?
Let’s start with how the Compose compiler transforms your Composables.
so below is the code which internally gets generated when we write fun Greetings() in our file.

- The compiler rewrites your
@Composablefunctions to accept extra hidden parameters. This help Compose track what parts of the UI depend on what state. So this makes Compose state aware.

- It marks the start of a recomposition group and uses this group key to remember this part of the UI tree.
Greeting( / ** / ) is one group. The Text( / ** / ) inside it might be another. These groups are tracked in a Slot Table, which is an internal structure that stores what was composed last time.
- What this unique group key does? -> in startRestartGroup() it calls unique key helps Compose find this group in the Slot Table.
What the Composer and changed flags are?
- Next is when the Compose compiler transforms your
@Composablefunction, it adds a hiddenchanged parameter. - If the
namedidn’t change it will skip re-running, thechangedflag makes this check fast.
How recomposition is skipped using bitmasks?
- As we know it starts with
startRestartGroup(...)and ends withendRestartGroup(). - These flags act as bitmasks — each bit represents whether a parameter may have changed.
- When Compose decides that nothing has changed in a recomposition group, it can skip executing the code for that group.
- But it still needs to advance its internal pointer in the Slot Table to the end of that group, so it stays in sync with the tree.
- This means if something changed: run the code other wise call skipToGroupEnd().
If we didn’t skip it might read the wrong slots. see bugs like reused state in the wrong places — or crashes.
Job Offers
What “groups” and “slot tables” mean in Compose?
- A group is just a section of your UI tree that Compose tracks as a unit.
- This lets Compose do partial recomposition instead of re-building the whole screen as if a group’s inputs changed to re-run the group.
- Now slot tables is the structure of your UI tree (the groups and how they’re nested).
- It looks up the group and check what changed and then decides whether to run or skip.
- let think with eg. val count = remember { mutableStateOf(0) } -> Compose allocates a slot in the table to store that
count— and next time, it knows where to find it.
Compose knows what’s there, what changed, and what needs to update — so it can skip redrawing parts that didn’t change.
- These are the four essential things every developer should understand about the internal workings of
Text()in Compose.
Now, if you’ve gone through all the points above, you might be wondering: does Text() in Jetpack Compose use a TextView behind the scenes, like in traditional Android?
The answer is — it doesn’t. Instead, Text() is rendered directly onto a Canvas internally. When you call Text(), it delegates to BasicText(), which uses CoreText(). Inside CoreText(), a TextDelegatehandles layout by creating a Paragraph. Finally, that Paragraph paints the text directly onto a Canvas.
- That’s it for this deep dive into how
Textworks under the hood in Jetpack Compose. I hope this helped you see the magic behind a simple Composable! In my next blog, I’ll explore the internals ofderivedStateOfand how it keeps your UI efficient and smart. If you enjoyed this post, please give it a clap — your support motivates me to share more!
Take Care 🙂
This article was previously published on proandroiddev.com


