Question
Use @Parcelize Without kotlin-android-extensions in Kotlin
Question
How can I replace the Parcelize annotation from kotlinx.android.parcel after the kotlin-android-extensions plugin is deprecated? Specifically, how do I use @Parcelize without relying on that plugin?
Short Answer
You will learn that @Parcelize is now enabled by the separate kotlin-parcelize Gradle plugin and imported from kotlinx.parcelize.Parcelize. You will also see how to migrate an existing parcelable Kotlin class safely.
Concept
Parcelable is an Android interface used to serialize an object into a Parcel, a compact container Android uses to transfer data between components. For example, an app may put a parcelable object into an Intent, a Fragment argument Bundle, or a saved-state container.
Writing Parcelable manually requires boilerplate: implementing writeToParcel, defining a CREATOR, and reading fields back in the same order. Kotlin's @Parcelize annotation generates that boilerplate during compilation.
Previously, Parcelize support was provided by the kotlin-android-extensions plugin, alongside synthetic view accessors. That plugin is deprecated. Parcelize is now a separate feature:
- Enable the Gradle plugin:
kotlin-parcelize - Import the annotation:
kotlinx.parcelize.Parcelize - Keep implementing
Parcelable
Separating the plugin means an app can continue using Parcelize without keeping the deprecated Android Extensions plugin.
Mental Model
Think of Parcelable as a shipping form required by Android before an object can travel from one screen to another.
Writing Parcelable by hand means filling in every field of the form yourself. @Parcelize is an assistant that fills in the form automatically, but the assistant must be hired in Gradle first. The kotlin-parcelize plugin hires that assistant, and kotlinx.parcelize.Parcelize is the new name tag you place on the class.
Syntax and Examples
First, enable the Parcelize compiler plugin in the Android module.
// app/build.gradle.kts
plugins {
id("com.android.application")
kotlin("android")
kotlin("parcelize")
}
If the project uses Groovy Gradle syntax, use this instead:
// app/build.gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-parcelize'
}
Then use the new import and annotation:
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class User(
val id: Long,
val name: String
) : Parcelable
@Parcelize tells the Kotlin compiler to generate the Parcelable implementation for User. The class must still declare : Parcelable, because that is the Android interface consumers expect.
Step by Step Execution
Consider this class:
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class Product(
val sku: String,
val quantity: Int
) : Parcelable
What happens during a build:
- Gradle sees
kotlin("parcelize")(orid("kotlin-parcelize")) and enables Parcelize support for the module. - Kotlin reads
@Parcelizefromkotlinx.parcelize.Parcelize. - The Parcelize compiler plugin generates the code needed to write
skuandquantityto an AndroidParceland read them back. Productsatisfies theParcelablecontract without handwrittenwriteToParcelorCREATORcode.- Android code can place a
Productin APIs that accept parcelable values, such as aBundle.
For example:
val args = android.os.Bundle().apply {
putParcelable("product", Product("A-42", 3))
}
Real World Use Cases
Common uses for @Parcelize include:
- Navigation arguments: pass a selected product, user, or filter object between Android destinations.
- Fragment arguments: store small screen inputs in a
Bundle. - Activity intents: send a parcelable object when starting another activity.
- Saved UI state: preserve small state objects across Android process recreation when an API requires
Parcelable. - Android service or callback boundaries: transfer structured data through Android framework APIs that accept parcelables.
Parcelable objects are best kept reasonably small. They are for Android component boundaries, not for long-term database storage or large data transfers.
Real Codebase Usage
In a real Android project, Parcelize is usually configured once in every Android module that declares @Parcelize classes.
A common model looks like this:
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class SearchFilters(
val query: String = "",
val onlyInStock: Boolean = false,
val categoryIds: List<Long> = emptyList()
) : Parcelable
Developers commonly use these patterns:
- Keep UI transport models small: pass an ID when a screen can load the full object from a repository.
- Use immutable
data classproperties:valfields make arguments predictable and easier to test. - Validate at the receiving boundary: a parcelable can be structurally valid while its values are not appropriate for the current screen.
- Separate module configuration: if
@Parcelizeis used in a feature or library module, enablekotlin-parcelizein that module too. - Avoid deprecated synthetic views: migration away from Android Extensions often also means replacing synthetic view access with View Binding or
findViewById; this is separate from Parcelize migration.
Common Mistakes
Keeping the old import
This old package belongs to the deprecated Android Extensions setup:
// Incorrect for the new setup
import kotlinx.android.parcel.Parcelize
Use:
import kotlinx.parcelize.Parcelize
Adding the annotation but not the Gradle plugin
This can leave the annotation unresolved or prevent Parcelize code generation:
@Parcelize
data class User(val name: String) : Parcelable
Add kotlin("parcelize") in Kotlin DSL or id 'kotlin-parcelize' in Groovy to the module's plugins block.
Forgetting : Parcelable
@Parcelize does not replace the interface declaration.
// Incorrect
@Parcelize
data class User(val name: String)
Correct:
@Parcelize
data class User(val name: String) : Parcelable
Configuring the wrong Gradle module
The plugin must be applied to the Android module containing the annotated class. Configuring it only in another module does not enable Parcelize there.
Using Parcelize for large payloads
Avoid passing large lists, bitmaps, or complete database objects between screens. Prefer passing a small identifier and loading the data again when appropriate.
Comparisons
| Approach | Purpose | Recommended use |
|---|---|---|
kotlin-android-extensions | Former plugin that bundled synthetic views and Parcelize | Do not add it for new code; it is deprecated |
kotlin-parcelize | Dedicated compiler plugin for @Parcelize | Use this for parcelable Kotlin classes |
Manual Parcelable | You write parcel read/write logic and CREATOR yourself | Use only when generated behavior is insufficient |
Serializable | Java object serialization interface | Usually avoid for Android component arguments; Parcelable is designed for Android |
| Passing an ID | Sends only a lightweight identifier | Prefer when the destination can retrieve the full data itself |
The migration changes both the Gradle plugin and import package, but the class structure remains familiar: @Parcelize plus : Parcelable.
Cheat Sheet
// app/build.gradle.kts
plugins {
kotlin("parcelize")
}
// app/build.gradle
plugins {
id 'kotlin-parcelize'
}
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class Example(
val id: Long,
val title: String
) : Parcelable
- New annotation package:
kotlinx.parcelize.Parcelize - Old annotation package:
kotlinx.android.parcel.Parcelize - Do not use
kotlin-android-extensionssolely for Parcelize. - Apply
kotlin-parcelizein each module that contains@Parcelizeclasses. - A Parcelize class must implement
Parcelable. - Keep objects passed through
BundleorIntentsmall.
FAQ
What replaces kotlin-android-extensions for @Parcelize?
Use the separate kotlin-parcelize Gradle plugin.
What is the new import for @Parcelize?
Use import kotlinx.parcelize.Parcelize.
Do I still need to implement Parcelable?
Yes. Declare : Parcelable; the annotation generates its required implementation.
Do I need to write writeToParcel manually with @Parcelize?
No. The Parcelize compiler plugin generates the normal parceling code.
Why is Parcelize unresolved after changing the import?
Usually the module has not applied the kotlin-parcelize plugin, or Gradle sync has not completed.
Can I keep kotlin-android-extensions just for Parcelize?
It is better to migrate to kotlin-parcelize, which provides Parcelize independently of the deprecated plugin.
Should every Android module apply kotlin-parcelize?
Only modules that declare classes annotated with @Parcelize need it.
Mini Project
Description
Create a small parcelable screen-argument model for a product details flow. This mirrors a common Android navigation task: one screen selects a product and another screen receives the values needed to render it.
Goal
Define a ProductPreview Kotlin data class that Android can place in and retrieve from a Bundle.
Requirements
Add the kotlin-parcelize plugin to the Android module.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.