Two options:
1) have an “empty” main project uniting your 3 subprojects:
root \--- project \--- Build.scala \--- web_ui \--- common \--- desktop_ui
And in Build.scala something like this:
lazy val common = Project(id = "common", base = file("common")) lazy val desktopUi = Project(id = "desktop_ui", base = file("desktop_ui") lazy val webUi = play.Project(name = "web_ui", path = file("web_ui")) .dependsOn(common, desktopUi)
lazy val root = Project (id = "root", base = file (".")). aggregate (common, desktopUi, webUi)
With this option, you can run sbt from the root folder and collect all your projects. You also define all settings, dependencies in this unique assembly definition.
2) Another layout can be used to make your subprojects independent of each other. I prefer this method because it is cleaner (for example, I can work on common as an independent project, and not as a submodule), but it is not so convenient to build the whole system.
root \--- web_ui \--- project \--- Build.scala \--- common \--- project \--- Build.scala \--- desktop_ui \--- project \--- Build.scala
Here, each project is independent (you can use build.sbt instead of Build.scala, if you want, see the sbt documentation) and in web_ui / project / Build.scala:
lazy val common = RootProject(file("../common")) lazy val desktopUi = RootProject(file("../desktop_ui")) val main = play.Project(name = "web_ui", path = file("web_ui")).dependsOn(common, desktopUi)
Here root is used only for collecting in only one folder, then the playback project refers to other modules.