Builds (Gradle)
For building our application, we are going to use Gradle, a modern build system that provides more functionality than make
and is more suitable for complex projects. Gradle is popular in the Kotlin and Java ecosystems, and is the Google-endorsed build tool for Android projects.
Gradle is always setup in the context of a project
: a specific directory structure, and a set of configuration files that define how your source code will be built. You create the Gradle project, and then your source code (and other assets) are added to that directory structure.
Setup
Gradle should be setup as the build system when you create your project in IntelliJ or Android Studio. Projects can be created with a variety of configurations, but for this course, you should choose Kotlin
as your programming language, Gradle
for your build system, and Kotlin
for your DSL language.

The result of this process is a new project with a directory structure and configuration files that are ready to use with Gradle. Note that the project will be specific to the type of project that you chose e.g., Android, Desktop, Web Service.
The section below will describe the different styles of projects in more detail.
Wrapper
At the top-level of your project’s directory structure will be a script named gradlew
(or gradlew.bat
for Windows users). This is the Gradle wrapper: a script that you can use to run Gradle tasks without having to install Gradle on your machine. You can run it and pass it the same command-line arguments that you would normally pass to Gradle.
$ ./gradlew help
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :help
Welcome to Gradle 7.5.1.
To run a build, run gradlew <task> ...
To see a list of available tasks, run gradlew tasks
To see more detail about a task, run gradlew help --task <task>
To see a list of command-line options, run gradlew --help
For troubleshooting, visit https://help.gradle.org
Gradle Tasks
To run Gradle tasks from the command line, use the Gradle wrapper with the appropriate the task name. We can run ./gradlew tasks
to see a list of tasks that are supported in your project. Commonly used tasks include:
./gradlew help
will provide online help../gradlew tasks
will list all of the tasks that are available../gradlew clean
will remove temporary build files../gradlew build
will build your project../gradlew run
will usually run your project (depending on the platform).
IntelliJ IDEA and Android Studio also allow you to run Gradle tasks directly within the IDE, as long as the Gradle plugin is installed.

Build Configuration
When you create a new project with Gradle, it will create a directory structure for you. This directory structure is opinionated: Gradle requires a specific directory structure to work correctly, so you should work within the structure that it gives you.
The sections below describe the different types of projects that you can create.
Single-Target Desktop
The default Gradle project is meant to build a console or desktop application. All code resides in a single module e.g., app
in the example below.
To create this style of project, launch IntelliJ IDEA.
- From the Splash screen in IntelliJ IDEA, select
New Project
, andKotlin
as the project type. Name
is the name of the folder that will contain your source code. e.g., “DesktopApp”, andLocation
is the location of your Git working copy.- Click
Create
to proceed. If successful, IntelliJ IDEA will open into the main window to a starting project.
Your project should have this structure.

Explanation
app
: the top-level code module.build.gradle.kts
: the main Gradle configuration file, specific to this module.src/main
: source code locationsrc/test
: corresponding unit tests
gradle
: the Gradle configuration fileslibs.version.toml
: the “version catalog” which contains dependency info (see below)wrapper/gradle-wrapper.jar
: bootstrap Gradle downloaderwrapper/gradle-wrapper.properties
: information on Gradle version, download location
gradle.properties
: optional environment variablesgradlew
: Gradle wrapper (see above)gradlew.bat
: Gradle wrapper (see above)settings.gradle.kts
: top-level configuration file
Single-Target Android
If you have the Android plugin installed in IntelliJ, you will have the option to create a dedicated Android project.
You normally create an Android project in the IntelliJ New Project Wizard, and using one of the Android
templates. I typically use the Empty Activity.
From the Splash screen in Android Studio:
- Select
New Project
. - Select
Empty Activity
andNext
.
A second screen will prompt you for project parameters. Fill in the following:
Name
: Your application namePackage name
: A unique package name.Save location
: Your working copy location.Minimum SDK
: API 26 or later.Build configuration language
: Kotlin DSL.
Click Finish
and your project should be created. Your directory structure will be the same as the Desktop example, with a couple of differences:
- You will have
Test
andAndroidTest
for test source sets, instead of a single folder. - You will have a
Manifest
file in the root of your project which contains Android specific configuration information. - Your application will launch from a
MainActivity.kt
file instead ofMain.kt
.
Multi-Project (App+Lib)
What do you do if you want to build a more complex project e.g., a combination of desktop, Android, web service and so on? In Gradle, this is known as a multi-project build
, and it allows you to build multiple projects from a single top-level project.
This structure is useful when you have multiple projects that depend on each other, or when you want to share code between projects.
There is a specific structure that you need to follow to create a multi-project build. In the example below, we have subprojects application, models and server which represent different projects.
You would typically create this project by using the IntelliJ New Project Wizard to create a starting project and then manually adding the others. Creating this structure isn’t directly supported by the IDE.
.
├── application
│ ├── build.gradle.kts
│ └── src
├── gradle
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── models
│ ├── build.gradle.kts
│ └── src
├── server
│ ├── build.gradle.kts
│ └── src
└── settings.gradle.kts
Notice that the top-level modules have been named application
, models
, server
. Each of these represents a different type of project, with it’s own build.gradle.kts file that defines how that particular module should be built. e.g.,
application
is a console application, so itsbuild.gradle.kts
will contain a plugin forapplication
. If you build that sub-project, you will get that style of application produced.models
is a shared library, meaning that it contains classes that are imported by both theapplication
andserver
projects. e.g., data classes.server
is a server, which runs standalone on a web server. It has specific server-like dependencies e.g., Ktor. If you build this project, you get a JAR file that can be installed on a web server.
To create a multi-project build, you need to create subprojects for each project that you want to manage. Each subproject should have its own build.gradle.kts
file, and a src
directory containing the source code for that project. The top-level settings.gradle.kts
describes common dependencies and the overall project structure.
Kotlin Multiplatform (KMP)
This project-type is suitable for targetting two or more targets with your application e.g., Desktop/JVM + Android. If you don’t mind the folder structure, it can also be used for any single project as well!
From the Splash screen in IntelliJ IDEA:
- Select
New Project
. - Choose
Kotlin Multiplatform
from the list of project types.
Provide the following:
Name
is the name of the folder that will contain your source code. e.g., “DesktopApp”.Location
is the location of your working copy (from Step 1 above).Group
is a reverse-DNS name, used for the top-level package name.Artifact
is the single-word name of the project.JDK
should point to your JDK installation (see toolchain).
Select the platforms that you wish to target, and enable Share UI
(which will default to using Compose for all platforms).
Click Create
to proceed. If successful, IntelliJ IDEA will open into the main window to an empty project.

You should be able to expand the folders to an individual target under the composeApp
folder, and click the Run
button in the toolbar to execute it.
FAQ
How do I specify the version of Gradle?
The Gradle project configuration (gradle/gradle-wrapper.properties
) lists the version of Gradle to be used for your project.
To change the version of Gradle being used, update the gradle-wrapper.properties
file, and change the distributionURL
line to the correct version e.g., Gradle 8.0.2 below.
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
The gradle-wrapper.properties
file should be stored in Git, as part of your build configuration scripts.
How can I tell Gradle what version of the JDK to use?
Gradle will use the JDK in the class path on your system to execute tasks. If you are using IntelliJ IDEA, you can also specify the version to use in the IDE settings: Settings > Build Tools > Gradle
.
Often you want to tell Gradle to compile your code with a specific JDK version. You can specify this in your project configuration files. For example, here’s how you specify JDK 21.
// add this to your build.gradle.kts
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
// add this to your settings.gradle.kts so Gradle can download the JDK
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0")
}
How do I create an installer for my program?
For a Compose desktop application, there is a set of Gradle packaging tasks: Gradle > application > Tasks > compose desktop > package
. You probably want to packageDistributionForCurrentOS
which will build a regular installer for the OS that you’re currently using.
For Android, it’s acceptable to build an APK file (Build
> Generate APK
) instead of a full installer. This file can be drag-dropped onto a running AVD to run the program.
There are also third-party installation tools if you want something more sophisticated. e.g. Conveyor.
How can I fix an installer that fails?
Here are some common errors to watch out for (all related to the build.gradle.kts
configuration file):
- You need to specify that you want to include all modules in the installer.
nativeDistributions {
includeAllModules = true
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "cs346-project"
packageVersion = "1.0.0"
}
- The version property defaults to “1.0-SNAPSHOT”. You MUST change this to the format “1.0.0” - see Semantic Versioning. You should probably be incrementing this with each software release/demo.
group = "com.example"
version = "1.0.0"
- It often takes some time for libraries to be updated to the “newest” JDK release. Best-practice is to use a JDK that has been stable for some time to avoid incompatibilty issues (see required software). Make sure to set the JDK in the project settings (
File
>Project Structure
>Project
) and the Gradle project settings (IntelliJ
>Settings
>Build
>Gradle
)
If your installer fails when you execute it, try checking some of the other related tasks in the Gradle Menu in IntelliJ. e.g. compose desktop
> runDistributable
. The Gradle tasks in this section represent the subtasks that the installer builds
and if you run them in the IDE, you will get more detailed feedback than you would from running the installer manually.
Final Word
It’s staggering how much software is available through package repositories…
