Lightbuild Hero Banner

Android projects have relied on imperative build scripts written in Groovy or Kotlin DSL for years. Because Gradle executes these scripts during its configuration phase, IDE sync times grow as you add modules. Modifying imperative scripts also presents syntax and scoping challenges for AI coding assistants.

At Android Dev Summit, Google introduced Lightbuild: an experimental declarative build system that represents project structure in YAML and uses pre-resolved dependency lockfiles (resolved.deps).

In this codelab, you will migrate ICanHazStream (me.kartikarora.icanhazstream), a multi-module Jetpack Compose streaming availability app, from Gradle convention plugins to Lightbuild YAML.

Prerequisites

1. Clone the Project

Clone the repository and check out the starter branch:

git clone https://github.com/kartikarora/ICanHazStream.git
cd ICanHazStream

# Check out the starter branch
git checkout lightbuild-start

# Create your personal migration branch to work in
git checkout -b my-lightbuild

The starting code on lightbuild-start is a complete, working multi-module Jetpack Compose app that uses:

2. Enable Preview Flags

Lightbuild is currently in early preview. Enable the experimental flag in your shell profile or terminal:

export ANDROID_CLI_BUILD=true

In Android Studio Canary, open Help > Edit Custom Properties... and add:

lightbuild.enable=true

Restart Android Studio after saving the file.

Lightbuild Transpilation Pipeline

Lightbuild does not replace the Android Gradle Plugin (AGP), D8, or R8. It sits in front of Gradle as a declarative frontend that passes structured data down to the underlying build engine.

Core Configuration Files

  1. project.lightbuild.yaml (Workspace Root):Replaces settings.gradle.kts and root build scripts. Declares active modules, repositories, and compiler versions.

  2. lightbuild.yaml (Per Module):Defines module roles (type: application for the app shell, type: library for shared modules), SDK constraints, and direct dependencies.

  3. resolved.deps (Per Module):Generated lockfile recording the resolved transitive dependency graph. Android Studio reads this file directly, removing remote network queries and transitive tree calculation during project sync.

ICanHazStream/
├── project.lightbuild.yaml       # Workspace manifest
├── app/                          # App Shell module (assembly only)
│   ├── lightbuild.yaml           # type: application
│   └── resolved.deps             # Lockfile
├── app-core/                     # Core App Library module
│   ├── lightbuild.yaml           # type: library
│   ├── resolved.deps
│   └── src/                      # App source code (MainActivity, StreamNavGraph)
├── core/
│   ├── ui/                       # type: library
│   ├── model/                    # type: library
│   ├── data/                     # type: library
│   └── testing/                  # type: library
└── feature/
    ├── explore/                  # type: library
    ├── detail/                   # type: library
    └── watchlist/                # type: library

ICanHazStream Modular Architecture

Create project.lightbuild.yaml in the root of the project:

project:
  name: "ICanHazStream"

modules:
  - app
  - app-core
  - core/model
  - core/data
  - core/ui
  - core/testing
  - feature/explore
  - feature/detail
  - feature/watchlist

repositories:
  - google
  - mavenCentral

lightbuild:
  version: "0.0.30"

build:
  java:
    version: "21"

This single data file replaces module declarations in settings.gradle.kts and common repository blocks. Android Studio Canary validates this file in real time using an embedded schema.

In Lightbuild projects, application modules are strictly empty assembly shells. They configure the application ID, version codes, and SDK constraints, but do not host application source code directly. All application logic, entry points (MainActivity), and navigation graphs reside in a separate library module (app-core).

1. App Shell: `app/lightbuild.yaml`

Create app/lightbuild.yaml configuring the thin assembly shell that depends on //app-core:

type: application
platform: android

android:
  namespace: me.kartikarora.icanhazstream
  applicationId: me.kartikarora.icanhazstream
  versionCode: 1
  versionName: "1.0"
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  targetSdk:
    version:
      release:
        apiLevel: 36
  dependencies:
    module:
      - //app-core

2. App Core Library: `app-core/lightbuild.yaml`

Move the Kotlin source code (MainActivity.kt and StreamNavGraph.kt) into app-core/src/main/kotlin/ and create app-core/lightbuild.yaml:

type: library
platform: android

android:
  namespace: me.kartikarora.icanhazstream
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  dependencies:
    module:
      - //feature/explore
      - //feature/detail
      - //feature/watchlist
      - //core/model
      - //core/data
      - //core/ui
    maven:
      - androidx.core:core-ktx:1.10.1
      - androidx.lifecycle:lifecycle-runtime-ktx:2.6.1
      - androidx.activity:activity-compose:1.8.0
      - androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1
      - androidx.lifecycle:lifecycle-runtime-compose:2.6.1
      - org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3

Inter-module dependencies use the //path/to/module syntax. External dependencies are listed under maven:.

Modules containing business logic, data sources, and UI components are configured as type: library. Android libraries require compileSdk and minSdk, but omit targetSdk and applicationId.

1. `:core:model/lightbuild.yaml`

type: library
platform: android

android:
  namespace: me.kartikarora.icanhazstream.model
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  dependencies:
    maven:
      - org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3
      - org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0

2. `:core:data/lightbuild.yaml`

type: library
platform: android

android:
  namespace: me.kartikarora.icanhazstream.data
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  dependencies:
    module:
      - //core/model
    maven:
      - io.ktor:ktor-client-core:2.3.9
      - io.ktor:ktor-client-okhttp:2.3.9
      - io.ktor:ktor-client-content-negotiation:2.3.9
      - io.ktor:ktor-serialization-kotlinx-json:2.3.9
      - org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0

3. `:core:ui/lightbuild.yaml`

type: library
platform: android

android:
  namespace: me.kartikarora.icanhazstream.ui
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  dependencies:
    module:
      - //core/model
    maven:
      - androidx.core:core-ktx:1.10.1
      - androidx.activity:activity-compose:1.8.0
      - androidx.compose.ui:ui:1.6.0
      - androidx.compose.ui:ui-graphics:1.6.0
      - androidx.compose.ui:ui-tooling-preview:1.6.0
      - androidx.compose.material3:material3:1.2.0

4. `:feature:explore/lightbuild.yaml`

type: library
platform: android

android:
  namespace: me.kartikarora.icanhazstream.feature.explore
  compileSdk:
    version:
      release:
        apiLevel: 36
  minSdk:
    version:
      release:
        apiLevel: 24
  dependencies:
    module:
      - //core/model
      - //core/data
      - //core/ui
    maven:
      - androidx.compose.ui:ui:1.6.0
      - androidx.compose.ui:ui-tooling-preview:1.6.0
      - androidx.core:core-ktx:1.10.1
      - androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1
      - androidx.lifecycle:lifecycle-runtime-compose:2.6.1
      - androidx.compose.material3:material3:1.2.0

Follow the same pattern for :feature:detail, :feature:watchlist, and :core:testing.

Run the resolution command to calculate and freeze dependencies:

android build resolve

Understanding `resolved.deps`

Review the generated app/resolved.deps and core/data/resolved.deps files:

# This file is automatically generated by Lightbuild.
# This file should be checked into version control.
sourceSets:
  main:
  - androidx.activity:activity:1.8.0
  - androidx.activity:activity-compose:1.8.0
  - androidx.activity:activity-ktx:1.8.0
  - androidx.annotation:annotation:1.6.0
  - androidx.annotation:annotation-experimental:1.3.0
  - androidx.annotation:annotation-jvm:1.6.0
  - androidx.compose.runtime:runtime:1.0.1
  - androidx.compose.ui:ui:1.0.1
  - androidx.core:core:1.10.1
  - androidx.core:core-ktx:1.10.1
  - androidx.lifecycle:lifecycle-runtime:2.6.1
  - androidx.lifecycle:lifecycle-viewmodel:2.6.1

Commit resolved.deps to git. When someone opens the project or runs a build, Android Studio reads this file directly, avoiding network lookups and version graph recalculations.

Deterministic Agent Automation Loop

Because Lightbuild configurations are structured data, automated coding assistants can parse and edit project setups with fewer errors.

Prompt your assistant (such as Gemini in Android Studio):

Add a new feature module called ':feature:reviews' to ICanHazStream.
1. Add 'feature/reviews' to project.lightbuild.yaml modules list.
2. Create 'feature/reviews/lightbuild.yaml' as type: library with dependencies on core/model, core/ui, and Compose Material 3.
3. Add feature/reviews to app/lightbuild.yaml dependencies.

The agent edits exact YAML fields without having to balance Kotlin DSL brackets or resolve version catalog conventions.

After the edit completes, run:

android build resolve

Verify the configuration using the unified Android CLI:

# Query targets and source sets
android build query --output sourcesets

# Run test targets
android build test

# Compile the debug application
android build app

The compiled APK will be located at app/build/app-debug.apk.