Basic concepts¶
Project and modules¶
An Amper project is defined by a project.yaml file. This file contains the list of modules and the project-wide
configuration. The folder with the project.yaml file is the project root. Modules can only be located under the
project root (at any depth). If there is only one module in the project, the project.yaml file is not required.
An Amper module is a directory with a module.yaml configuration file, and optionally sources and resources.
A module configuration file describes what to produce: e.g. a reusable library or a platform-specific application.
Each module describes a single product. Several modules can't share the same sources or resources, but they can depend
on each other.
How to produce the desired product, that is, the build rules, is the responsibility of the Amper build engine.
If you are not familiar with YAML, see our brief YAML primer.
Project layout¶
Single-module project¶
A single-module Amper project doesn't need a project.yaml file.
Just create a single valid module, and it is also a valid project1:
my-project/ #(1)!
├─ src/
│ ├─ main.kt
├─ test/
│ ╰─ MainTest.kt
╰─ module.yaml
- This is the project root but also the root of the only module in the project.
See the Module layout section for more details about the module structure itself.
Multi-module project¶
If there are multiple modules, the project.yaml file specifies the list of modules:
├─ app/
│ ├─ src/
│ │ ├─ main.kt
│ │ ╰─ ...
│ ╰─ module.yaml
├─ libs/ #(1)!
│ ├─ lib1/
│ │ ├─ src/
│ │ │ ╰─ myLib1.kt
│ │ ╰─ module.yaml
│ ╰─ lib2/
│ ├─ src/
│ │ ╰─ myLib2.kt
│ ╰─ module.yaml
╰─ project.yaml
- This hierarchy is arbitrary, it can be organized however you like. The structure is understood by Amper based on
the list of module paths in
project.yaml— there is no convention for multi-module projects.
modules:
- ./app
- ./libs/lib1 #(1)!
- ./libs/lib2
product: jvm/app
dependencies:
- ./libs/lib1
- ./libs/lib2
- It is also possible to use globs to list multiple modules at once (e.g.,
./libs/*), although we encourage listing them explicitly. See details in the project file reference.
See the Module layout section for more details about what goes inside each module directory.
Multi-module project with root module
It is also possible to have a root module even if there are multiple modules in the project, although this is generally discouraged.
├─ lib/
│ ├─ src/
│ │ ╰─ util.kt
│ ╰─ module.yaml
├─ src/ # src of the root module
│ ├─ main.kt
│ ╰─ ...
├─ module.yaml # the module file of the root module
╰─ project.yaml
modules: # The root module is included implicitly
- ./lib
Module layout¶
Here are typical module structures at a glance:
my-module/
├─ resources/ # (1)!
│ ╰─ logback.xml # (2)!
├─ src/
│ ├─ main.kt
│ ╰─ Util.java # (3)!
├─ test/
│ ╰─ MainTest.java # (4)!
│ ╰─ UtilTest.kt
├─ testResources/
│ ╰─ logback-test.xml # (5)!
╰─ module.yaml
- Resources placed here are copied into the resulting jar.
- This is just an example resource and can be omitted.
- You can mix Kotlin and Java source files in a single module, all in the
srcfolder. - You can test Java code with Kotlin tests or Kotlin code with Java tests.
- This is just an example resource and can be omitted.
Maven compatibility layout for JVM-only modules
If you're migrating from Maven, you can also configure the Maven-like layout
my-module/
├─ resources/ # common resources, used in all targets
├─ resources@ios/ # resources that are only available to the iOS code
├─ resources@jvm/ # resources that are only available to the JVM code
├─ src/ # common code, compiled for all targets
│ ├─ main.kt
│ ╰─ util.kt # (1)!
├─ src@native/ # code to be compiled for all native targets
├─ src@apple/ # code to be compiled for all Apple targets
├─ src@ios/ # code to be compiled only for iOS targets
│ ╰─ util.kt # (2)!
├─ src@jvm/ # code to be compiled only for JVM targets
│ ├─ util.kt
│ ╰─ MyClass.java # (3)!
├─ test/ # common tests, compiled for all targets
│ ╰─ MainTest.kt
├─ test@ios/ # tests that are only run on iOS simulator
│ ╰─ SomeIosTest.kt
├─ test@jvm/ # tests that are only run on JVM
│ ╰─ SomeJvmTest.kt
├─ testResources/ # common test resources, used in all targets
├─ testResources@ios/ # test resources that are only available to the iOS code
├─ testResources@jvm/ # test resources that are only available to the JVM code
╰─ module.yaml
- This file may define
expectdeclarations to be implemented differently on different platforms. - This file defines the
actualimplementations corresponding to theexpectdeclarations fromsrc. - It's ok to have Java sources in JVM-only source directories.
Read more in the dedicated Multiplatform modules section.
my-android-app/
├─ assets/ # (1)!
├─ res/ # (2)!
│ ├─ drawable/
│ │ ╰─ graphic.png
│ ├─ layout/
│ │ ├─ main.xml
│ │ ╰─ info.xml
│ ╰─ ...
├─ resources/
├─ src/
│ ├─ AndroidManifest.xml # (3)!
│ ╰─ MainActivity.kt # (4)!
├─ test/
│ ╰─ MainTest.kt
├─ module.yaml
╰─ proguard-rules.pro # (5)!
assetsandresare standard Android resource directories. See the official Android docs.assetsandresare standard Android resource directories. See the official Android docs.- The manifest file of your application.
- An activity (screen) of your application.
- Optional configuration for R8 code shrinking and obfuscation. See code shrinking.
Read more in the dedicated Android section.
my-ios-app/
├─ src/
│ ├─ KotlinCode.kt # (1)!
│ ├─ EntryPoint.swift # (2)!
│ ╰─ Info.plist
├─ module.yaml
╰─ module.xcodeproj # (3)!
- Kotlin code is optional. Everything could come from dependencies.
- The entrypoint of iOS apps must be a
@mainstruct in a Swift file. Read more - An Xcode project is required but it can be automatically generated by Amper the first time. Read more
Read more in the dedicated iOS section.
All sources and resources are optional: only the module.yaml file is required.
For example, your module could get all its code from dependencies and have no src folder.
Sources and resources can't be defined as part of multiple modules — they must belong to a single module, which other modules can depend on. This ensures that the IDE always knows how to analyze and refactor the code, as it always has a single well-defined set of settings and dependencies.
Module file anatomy¶
A module.yaml file has several main sections: product, dependencies and settings.
A module can produce a single product, such as a reusable library or an application. Read more on the supported product types below.
Here are some example module files for different types of modules:
product: jvm/app #(1)!
dependencies:
- io.ktor:ktor-client-java:2.3.0 #(2)!
settings: #(3)!
kotlin:
version: 2.2.21 #(4)!
allWarningsAsErrors: true #(5)!
- This short form is equivalent to:
The
product: type: jvm/appjvm/appproduct type means that the module produces a JVM application. - The
dependenciessection contains the list of dependencies for this module. Hereio.ktor:ktor-client-core:2.3.0are the Maven coordinates of the Ktor client library (with Java engine). Read more about dependencies in general in the Dependencies section. - The
settingssection contains the configuration of different toolchains. - An example setting: the Kotlin compiler version used for this module.
- An example setting: a compiler setting to consider warnings as errors and fail the build on any warning.
product:
type: lib #(1)!
platforms: [android, iosArm64, iosSimulatorArm64] #(2)!
dependencies:
- io.ktor:ktor-client-core:2.3.0 #(3)!
dependencies@android:
- io.ktor:ktor-client-android:2.3.0 #(4)!
dependencies@ios:
- io.ktor:ktor-client-darwin:2.3.0 #(5)!
settings: #(6)!
kotlin:
version: 2.2.21 #(7)!
allWarningsAsErrors: true #(8)!
settings@ios: #(9)!
kotlin:
allWarningsAsErrors: false #(10)!
- The
libproduct type means that the module produces a Kotlin Multiplatform library. - The
platformslist contains the platforms that this module is built for. - The
dependenciessection contains the list of common dependencies for this module. Hereio.ktor:ktor-client-core:2.3.0are the Maven coordinates of the Ktor client core library. Read more about dependencies in general in the Dependencies section. Read more about multiplatform dependencies in the Multiplatform dependencies section. - The
dependencies@androidsection contains the list of dependencies that are only used when building the module for the Android target. Here theio.ktor:ktor-client-android:2.3.0will not be present when building the module for the iOS targets. Read more about dependencies in general in the Dependencies section. Read more about multiplatform dependencies in the Multiplatform dependencies section. - The
dependencies@iossection contains the list of dependencies that are only used when building the module for the iOS target. Here theio.ktor:ktor-client-darwin:2.3.0will not be present when building the module for the Android target. Read more about dependencies in general in the Dependencies section. Read more about multiplatform dependencies in the Multiplatform dependencies section. - The
settingssection contains the configuration of different toolchains for common code, and also serves as default for platform-specific code.. - An example setting: the Kotlin compiler version used for this module.
- An example setting: a compiler setting to consider warnings as errors and fail the build on any warning.
- The
settings@iossection contains the configuration of different toolchains for iOS-specific compilation. - This setting overrides the one that we set in the
settingssection. Read more about this in the settings propagation section.
Product type¶
The product type describes the target platform and the type of the module at the same time. Below is the list of supported product types:
lib- a reusable Kotlin Multiplatform library which can be used as a dependency by other modules in the projectjvm/lib- a reusable JVM library which can be used as a dependency by other modules in the projectjvm/app- a JVM console or desktop applicationwindows/app- a mingw64 applicationlinux/app- a native Linux applicationmacos/app- a native macOS applicationandroid/app- an Android applicationios/app- an iOS application
Dependencies¶
The dependencies section contains the list of dependencies for this module.
They can be external maven libraries, other modules in the project, and more.
Please see the Dependencies section for more details.
Settings¶
The settings section contains toolchains settings.
A toolchain is an SDK (Kotlin, Java, Android, iOS) or a simpler tool (linter, code generator).
All toolchain settings are specified in dedicated groups in the settings section:
settings:
kotlin:
languageVersion: 1.8
android:
compileSdk: 31
Check out the Reference page for the full list of supported settings.
See the multiplatform section for more details about how multiple settings sections interact in multiplatform modules.
Configuring entry points¶
JVM¶
By default, the entry point of JVM applications (the main function) is expected to be in a main.kt file
(case-insensitive) in the src folder.
This can be overridden by specifying a main class explicitly in the module settings:
product: jvm/app
settings:
jvm:
mainClass: org.example.myapp.MyMainKt
Note
In Kotlin, unlike Java, the main function doesn't have to be declared in a class, and is usually at the top level
of the file. However, the JVM still expects a main class when running any application. Kotlin always compiles
top-level declarations to a class, and the name of that class is derived from the name of the file by capitalizing
the name and turning the .kt extension into a Kt suffix.
For example, the top-level declarations of myMain.kt will be in a class named MyMainKt.
Native¶
By default, the entry point of Kotlin native applications (the main function) is expected to be in a main.kt file
(case-insensitive) in the src folder.
This can be overridden by specifying the fully qualified name of the main function explicitly in the module settings:
product: linux/app
settings:
native:
entryPoint: org.example.myapp.main
Android¶
Android apps have their own way to configure the entry point, see the dedicated Android section.
iOS¶
iOS apps have their own way to configure the entry point, see the dedicated iOS section.
Packaging¶
Amper provides a package command to build a project for distribution.
For jvm/app modules it produces executable jars which follow
The Executable Jar Format.
The executable JAR format, while commonly associated with Spring applications, is a universal packaging solution
suitable for any JVM application. This format provides a convenient, runnable self-contained deployment unit that
includes all necessary dependencies, but unlike the "fat jar" approach, it doesn't suffer from the problems of handling
duplicate files.
For android/app modules, see the dedicated Android packaging section.
-
As long as it is not included in a
project.yamlhigher in the directory tree. ↩