Question

Use @Parcelize Without kotlin-android-extensions in Kotlin

kotlinandroidannotationsparcelable

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.

Take Quiz

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:

  1. Gradle sees kotlin("parcelize") (or id("kotlin-parcelize")) and enables Parcelize support for the module.
  2. Kotlin reads @Parcelize from kotlinx.parcelize.Parcelize.
  3. The Parcelize compiler plugin generates the code needed to write sku and quantity to an Android Parcel and read them back.
  4. Product satisfies the Parcelable contract without handwritten writeToParcel or CREATOR code.
  5. Android code can place a Product in APIs that accept parcelable values, such as a Bundle.

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.

Take Quiz

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 class properties: val fields 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 @Parcelize is used in a feature or library module, enable kotlin-parcelize in 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

ApproachPurposeRecommended use
kotlin-android-extensionsFormer plugin that bundled synthetic views and ParcelizeDo not add it for new code; it is deprecated
kotlin-parcelizeDedicated compiler plugin for @ParcelizeUse this for parcelable Kotlin classes
Manual ParcelableYou write parcel read/write logic and CREATOR yourselfUse only when generated behavior is insufficient
SerializableJava object serialization interfaceUsually avoid for Android component arguments; Parcelable is designed for Android
Passing an IDSends only a lightweight identifierPrefer 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.

Take Quiz

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-extensions solely for Parcelize.
  • Apply kotlin-parcelize in each module that contains @Parcelize classes.
  • A Parcelize class must implement Parcelable.
  • Keep objects passed through Bundle or Intent small.

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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more