Real‑world examples of diverse Kotlin data classes for modern development
Before definitions or theory, let’s jump straight into concrete code. Here are several examples of diverse examples of Kotlin data classes you’d actually see in a 2024+ codebase: network responses, pagination, value objects, UI state holders, and multiplatform models.
API response and pagination example of a Kotlin data class
A very common example of Kotlin data classes appears in REST or GraphQL clients. Think of a paged API from a backend or a third‑party service:
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class PagedResponse<T>(
@SerialName("items") val items: List<T> = emptyList(),
@SerialName("page") val page: Int = 1,
@SerialName("pageSize") val pageSize: Int = 20,
@SerialName("totalCount") val totalCount: Long = 0,
) {
val hasNextPage: Boolean get() = (page * pageSize) < totalCount
}
Here you see a few of the best examples of idiomatic patterns:
- Generics so the same container works for any item type.
- Default values to avoid boilerplate when testing.
- Computed properties (
hasNextPage) encapsulating logic instead of scattering it across the UI.
This is the kind of example of a Kotlin data class that keeps your pagination logic consistent across Android, desktop, or server modules.
Domain value object: Money and Currency
Money is a classic case where a small, well‑designed data class saves you from bugs. In an e‑commerce or fintech app, examples of diverse examples of Kotlin data classes often include value objects that enforce invariants:
import java.math.BigDecimal
import java.util.Currency
@JvmInline
value class CurrencyCode(val code: String) {
init {
require(code.matches(Regex("^[A-Z]{3}$"))) {
"Invalid currency code: $code"
}
}
}
data class Money(
val amount: BigDecimal,
val currency: CurrencyCode,
) {
operator fun plus(other: Money): Money {
require(currency == other.currency) {
"Cannot add different currencies: \(currency vs }\(other.currency}"
}
return copy(amount = amount + other.amount)
}
}
Here, examples include:
- A
value class(CurrencyCode) for type‑safety around plain strings. - A
Moneydata class with domain rules right next to the data.
In 2024, this pattern fits nicely with Kotlin’s push toward better type‑safety and inline value classes, especially on the JVM.
Android UI state: immutable screen model
Modern Android (Jetpack Compose, unidirectional data flow) leans heavily on immutable state objects. These are some of the best examples of diverse examples of Kotlin data classes because they show how to model screens, not just entities:
data class UserProfileUiState(
val isLoading: Boolean = false,
val errorMessage: String? = null,
val username: String = "",
val email: String = "",
val avatarUrl: String? = null,
val isEmailVerified: Boolean = false,
) {
val canResendVerification: Boolean
get() = !isLoading && !isEmailVerified && !email.isBlank()
}
Compose observers a single UserProfileUiState instance. When your ViewModel emits a new state, the UI recomposes. This example of a Kotlin data class shows:
- All screen data in one place instead of dozens of LiveData fields.
- Derived UI logic (
canResendVerification) kept close to the data.
If you’re following patterns recommended by Google’s Android docs (developer.android.com), your real examples will look very similar.
Network DTO vs domain model: mapping with data classes
Another category where examples of diverse examples of Kotlin data classes shine is the split between DTOs (for the network) and domain models (for business logic).
import kotlinx.serialization.Serializable
@Serializable
data class UserDto(
val id: String,
val name: String,
val email: String?,
val createdAt: String,
)
data class User(
val id: String,
val displayName: String,
val email: String?,
val createdAtMillis: Long,
)
fun UserDto.toDomain(clock: java.time.Clock): User {
val instant = java.time.Instant.parse(createdAt)
val millis = instant.toEpochMilli()
return User(
id = id,
displayName = name.trim(),
email = email?.lowercase(),
createdAtMillis = millis,
)
}
In this example of mapping between data classes:
UserDtomatches the API contract exactly.Useris tuned for your app’s needs (normalized name, epoch millis).
This pattern makes refactors safer when the backend changes. It also lets you write tests against domain models without mocking the entire network layer.
Sealed hierarchies with data classes for results
Kotlin’s sealed interfaces and classes pair nicely with data classes to model results, errors, and events. Many of the best examples of diverse examples of Kotlin data classes use this pattern for network and database calls:
sealed interface LoadResult<out T> {
data class Success<T>(val data: T) : LoadResult<T>
data class Error(val throwable: Throwable) : LoadResult<Nothing>
data object Loading : LoadResult<Nothing>
}
suspend fun <T> safeCall(block: suspend () -> T): LoadResult<T> =
try {
LoadResult.Success(block())
} catch (t: Throwable) {
LoadResult.Error(t)
}
Here, examples include:
- Two data classes (
Success,Error) and one singleton object. - A sealed interface
LoadResultfor exhaustivewhenhandling.
This pattern is common in Ktor, Retrofit + coroutines, and any codebase that wants predictable error handling.
Kotlin Multiplatform: shared models for mobile and backend
By 2024–2025, Kotlin Multiplatform (KMP) is far more common in production. Shared models are some of the most important real examples of diverse examples of Kotlin data classes, because they cross iOS, Android, and server boundaries.
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
@Serializable
data class HealthMetric(
val userId: String,
val type: MetricType,
val value: Double,
val unit: String,
val recordedAt: Instant,
)
@Serializable
enum class MetricType { HEART_RATE, STEPS, SLEEP_HOURS }
A shared HealthMetric can be used:
- In Android code to render charts.
- In iOS Swift code via generated bindings.
- On the server to store and aggregate data.
If you’re building anything around health or wellness, you might even align your naming or units with guidelines from sources like the U.S. National Institutes of Health (nih.gov) or Mayo Clinic (mayoclinic.org) to keep your models understandable to non‑developers.
Data classes for configuration and feature flags
Modern apps rely heavily on configuration: feature flags, A/B tests, remote settings. These are underrated examples of diverse examples of Kotlin data classes because they often start as simple maps and then grow into something much more complex.
import kotlinx.serialization.Serializable
@Serializable
data class FeatureFlags(
val newOnboardingEnabled: Boolean = false,
val useNewSearchEngine: Boolean = false,
val maxItemsPerPage: Int = 50,
val experimentGroup: String? = null,
)
@Serializable
data class RemoteConfig(
val apiBaseUrl: String,
val flags: FeatureFlags = FeatureFlags(),
)
With this structure:
- You can easily serialize/deserialize from JSON.
- You get type‑safety instead of magic strings.
- Tests can spin up different configurations with a single
copy()call.
If you’re doing experimentation or A/B testing in health or education apps, this pattern also makes it easier to document and audit changes, which is something regulators and researchers care about (see, for instance, reproducibility discussions in academic environments like harvard.edu).
Modeling events and analytics with data classes
Analytics events are another category where examples include many small, focused data classes. Instead of logging raw maps, you can define structured events:
import kotlinx.serialization.Serializable
@Serializable
data class AnalyticsEvent(
val name: String,
val properties: Map<String, String> = emptyMap(),
val timestampMillis: Long = System.currentTimeMillis(),
)
@Serializable
data class ScreenViewEvent(
val screenName: String,
val referrer: String? = null,
val timestampMillis: Long = System.currentTimeMillis(),
)
These real examples of diverse Kotlin data classes make your analytics pipeline easier to test and reason about. You can also version them explicitly if you need to evolve your event schema over time.
Data classes in coroutines and Flow pipelines
Kotlin coroutines and Flow often pass around small, immutable snapshots of state. Think of a repository emitting a stream of data + metadata:
data class RepositoryState<T>(
val data: T? = null,
val isRefreshing: Boolean = false,
val lastUpdatedMillis: Long? = null,
val error: Throwable? = null,
)
This example of a Kotlin data class is frequently wrapped in StateFlow<RepositoryState<T>> or SharedFlow<RepositoryState<T>>. The pattern keeps loading, success, and error information together, instead of spreading flags and exceptions across multiple channels.
Patterns and best practices drawn from these examples
Looking across all these examples of diverse examples of Kotlin data classes, a few patterns stand out:
Favor immutability and copy
Every example of a Kotlin data class above is immutable: val properties by default. When you need to change something, you call copy(). This works nicely with coroutines, Flow, and Compose, because it avoids weird race conditions and state leaks.
Keep behavior close to the data
Many of the best examples include computed properties or small helper methods inside the data class:
hasNextPageinPagedResponse.canResendVerificationinUserProfileUiState.plusinMoney.
This keeps your domain rules discoverable and testable.
Separate DTOs from domain models
UserDto vs User is not a theoretical exercise. In long‑lived codebases, it’s what keeps you from breaking everything when the backend team renames a field. Real examples of production Kotlin apps almost always have this split once they grow beyond a few screens.
Use serialization annotations sparingly but consistently
In the examples of diverse examples of Kotlin data classes that interact with the network, you saw @Serializable and @SerialName. Whether you use Kotlinx Serialization, Moshi, or Jackson, the pattern is the same: keep your wire format explicit, especially when talking to external APIs or regulated domains like healthcare or education, where you might also reference standards or public guidance from sites such as cdc.gov or webmd.com for terminology.
FAQ: short answers based on real examples
What are some practical examples of Kotlin data classes in everyday apps?
Practical examples include API response wrappers (PagedResponse), domain value objects (Money), UI state containers (UserProfileUiState), result wrappers (LoadResult), and configuration models (RemoteConfig, FeatureFlags). These examples of diverse examples of Kotlin data classes show up in almost every Android or backend project.
Can you show an example of a Kotlin data class with default values and validation?
Money and CurrencyCode are a good example of that pattern. CurrencyCode validates the format in init, while Money can enforce same‑currency arithmetic. Many real examples also add default values for optional fields to simplify testing.
Are data classes good for Kotlin Multiplatform shared code?
Yes. The HealthMetric example of a Kotlin data class is typical: it’s serializable, uses multiplatform types like Instant, and can be shared across Android, iOS, and server modules. This is one of the best examples of how data classes support code sharing in 2024–2025.
Should I put business logic inside data classes?
Lightweight logic is fine: derived properties, simple validation, or convenience methods. For heavier workflows, keep that in services or use cases. The examples include small helpers like hasNextPage and plus, but not entire workflows.
How do I avoid overusing data classes?
Use them where you’re modeling data with identity and equality. If a type has complex behavior, mutable state, or lifecycle responsibilities (like a ViewModel or repository), it probably shouldn’t be a data class. The real examples above keep data classes focused on modeling state, not orchestrating side effects.
By grounding your models in these kinds of real examples of diverse Kotlin data classes, you end up with code that’s easier to test, easier to read, and far less fragile when your product inevitably changes.
Related Topics
Real-world examples of diverse Kotlin coroutines in 2025
The best examples of Kotlin RecyclerView – 3 practical use cases for modern Android apps
Modern examples of 3 practical examples of Kotlin sealed classes in real apps
Real‑world examples of diverse Kotlin data classes for modern development
Explore More Kotlin Code Snippets
Discover more examples and insights in this category.
View All Kotlin Code Snippets