On this page
Introduction
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.
Project layout
A single-module Amper project doesn’t need a project.yaml file. Just create a single valid module, and it is also a valid project.
If there are multiple modules, the project.yaml file specifies the list of modules:
modules: - android-app - ios-app - jvm-app - sharedSources 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.
Getting started
Create a new “Compose Multiplatform application” with Amper - Compose
Specific module to run (run the show modules command to get the modules list)
.\amper run --module jvm-appDependencies
Module dependencies
To depend on another module of your project, use the path to that module, relative to the current module’s root directory. The path must start either with ./ or ../
For example, on the created project the jvm-app module declares a dependency on the shared module:
dependencies: - ../sharedDependencies between modules are only allowed within the project scope. That is, they must be listed in the project.yaml file and cannot be outside the project root directory.
Project Catalog
The project catalog is the user-defined catalog for the project.
It is defined in a file named libs.versions.toml, and is written in the TOML format of Gradle version catalogs.
Only [versions] and [libraries] sections are supported from the Gradle format, not [bundles] and [plugins].
To use dependencies from the project catalog, use the syntax $libs.<key> instead of the coordinates, where $libs is the catalog name of the project catalog, and <key> is defined according to the Gradle name mapping rules.
Example:
[versions]ktor = "3.3.2"
[libraries]ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor" }ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }ktor-client-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }dependencies: - $libs.ktor-client-auth - $libs.ktor-client-cio - $libs.ktor-client-contentNegotiationTransitivity and scope
By default, dependencies are available during both compilation and execution. However, you can change this behavior by specifying a scope or marking the dependency as exported.
Dependency scopes
There are three dependency scopes:
| Scope | Description |
|---|---|
all | (Default) The dependency is available during compilation and execution. |
compile-only | The dependency is only available during compilation. |
runtime-only | The dependency is not available during compilation, but is available during testing and execution. |
You can declare the scope using either a shorthand or a long-form syntax:
dependencies: # Shorthand syntax - io.ktor:ktor-client-core:3.4.0: compile-only - ../ui/utils: runtime-only
# Long-form syntax - io.ktor:ktor-client-cio:3.4.0: scope: compile-onlyExported dependencies
By default, dependencies of your module are not added to the compilation of dependent modules. In the following setup, app-jvm cannot directly use Ktor classes in its code:
dependencies: - io.ktor:ktor-client-core:3.4.0dependencies: - ../sharedTo make a dependency accessible to all dependent modules during their compilation, you need to explicitly mark it as exported.
dependencies: # Shorthand syntax - io.ktor:ktor-client-core:3.4.0: exportedYou can also use the long-form syntax, which is useful when combining exported with a specific scope:
dependencies: - io.ktor:ktor-client-core:3.4.0: scope: compile-only exported: trueIdeally, you should use exported dependencies as little as possible. The rule of thumb is that, if your module uses some types from the dependency in its public API, you should mark it as exported. If not, you should probably avoid it.
For example, if you depend on ktor-client-core in your module, and you have the following class:
class MyApi(private val client: HttpClient) { // ...}The HttpClient type is used in your public constructor, so your consumers will need to see it at compile time. You should therefore mark ktor-client-core as exported.
Templates
In modularized projects, there is often a need to have a certain common configuration for all or some modules. Typical examples could be a testing framework used in all modules or a Kotlin language version.
Amper offers a way to extract whole sections or their parts into reusable template files. These files are named <name>.module-template.yaml and have the same structure as module.yaml files.
A template is applied to a module.yaml file by adding it to the apply: section:
product: jvm/appapply: - ../common.module-template.yamltest-dependencies: - org.jetbrains.kotlin:kotlin-test:1.8.10
settings: kotlin: languageVersion: 2.2Sections in the template can also have @platform-qualifiers.
Template files can’t have product: and apply: sections (they can’t be recursive).
Templates are applied one by one, using the same rules as platform-specific dependencies and settings:
- Scalar values (strings, numbers etc.) are overridden.
- Mappings and lists are appended.
Settings and dependencies from the module.yaml file are applied last. The position of the apply: section doesn’t matter, the module.yaml file content always has precedence. E.g.
dependencies: - ../sharedsettings: kotlin: languageVersion: 2.2 compose: enabledproduct: jvm/appapply: - ./common.module-template.yamldependencies: - ../jvm-utilsettings: kotlin: languageVersion: 1.9 jvm: release: 8After applying the template the resulting effective module is:
product: jvm/appdependencies: # lists appended - ../shared - ../jvm-utilsettings: # objects merged kotlin: languageVersion: 1.9 # module.yaml overwrites value compose: enabled # from the template jvm: release: 8 # from the module.yaml