Separate multi-project deployment packages in Play! Framework

Play Framework projects can build from several Play / sbt projects. A common use case is to keep code modular and composable. The official documentation shows how to combine Play projects, but does not specifically show how to create separate deployment packages that each are composed of different services.

At FortyTwo, we use a single repository for our backend code. On deployment, however, our packages only contain the code they need. We had the following objectives:

  • Development should be simple. play run should be enough to run all services at the same time.
  • Common dependencies and modules should be easily shared.
  • We should be able to compile / test / run each service separately in development and production.
  • Deployment packages should contain only the classes that the service needs.
  • Routes should be split by service.

Play and SBT documentation show how to create a multi-project Build.scala file. When you run Play / sbt, you’ll load one of the projects by default. It makes whatever project variable name comes first alphebetically the default — so you’ll likely want to name your top-level project aaaMain or similar.

In the sbt console, you can see all of the projects with projects. To change the project, use project projectName. From there, you can compile / test independently.

We built a sample Play application to show how to do these ( Github repo). multiproject is the default top level project to be used in development, and uses two services.

Project structure

serviceA is like a user-facing web service. Its routes look like:

GET   /                  controllers.serviceA.Application.home()
GET   /serviceA          controllers.serviceA.Application.main()
GET   /serviceA/:name    controllers.serviceA.Application.greet(name: String)

serviceB’s routes look like:

GET   /serviceB          controllers.serviceB.Application.main()
GET   /serviceB/lottery  controllers.serviceB.Application.lottery()

Running multiple projects at onceIn multiproject, when you run play run, both serviceA and serviceB will run together, so you can work on either service and they can communicate to each other. multiproject is configured with Build.scala such that compile and test run across all sub-projects as well.

play.Project("multiproject", appVersion, commonDependencies ++ serviceADependencies ++ serviceBDependencies).settings().dependsOn(common, serviceA, serviceB).aggregate(common, serviceA, serviceB)
andrew$ play

[info] Set current project to multiproject (in build file:/Users/andrew/Documents/workspace/multiproject/)
       _            _
 _ __ | | __ _ _  _| |
| '_ | |/ _' | || |_|
|  __/|_|____|__ (_)
|_|            |__/

play! 2.1.1 (using Java 1.6.0_45 and Scala 2.10.0),

> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.

[multiproject] $ projects
[info] In file:/Users/andrew/Documents/workspace/mp2/
[info] common
[info] * multiproject
[info] serviceA
[info] serviceB
[multiproject] $ run

--- (Running the application from SBT, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0%0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

Additionally, you can also compile / test / run each service (or even the common package) independently.

[multiproject] $ project serviceA
[info] Set current project to serviceA (in build file:/Users/andrew/Documents/workspace/multiproject/)
[serviceA] $ test
[info] ApplicationSpec
[info] CommonApplication should
[info] + send 404 on a bad request
[info] + render the status page
... snip (sbt runs tests for just serviceA and common) ...
[serviceA] $ run
--- (Running the application from SBT, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0%0:9000

ServiceA runningNotice how serviceA only needed to compile and test serviceA and common, rather than everything. This is especially cool for deployments. While you get all the benefits of a unified codebase, you can deploy completely separate packages for each service.

[multiproject] $ dist
... snip ...
Your application is ready in /Users/andrew/Documents/workspace/multiproject/modules/common/dist/

Your application is ready in /Users/andrew/Documents/workspace/multiproject/dist/

Your application is ready in /Users/andrew/Documents/workspace/multiproject/modules/serviceB/dist/

Your application is ready in /Users/andrew/Documents/workspace/multiproject/modules/serviceA/dist/

Since each of these are self contained, your deployment manager can push these distributions to their respective application servers.

As a note, since each deployment will not have all of the classes, the default Play reverse router will not be able to determine URLs cross-service. You will likely want to write your own reverse router in a common module.

Clone the separate multi-project deployment packages git repository on Github to play with this.

We wrote this post while working on Kifi — Connecting people with knowledge. Learn more.

Xuyen Le
Xuyen Le


im have problem that i want create dynamic url depend module. ex:

String module; ex:  serviceA or serviceB

String url= controllers.module.routes.ModuleController
                      .usergroups().url() // module is var

i can't find any ideal 

can you help me

thanks you so much.



I'm testing your project, but when i run with activator, the subproject "serviceA", it print the "No router defined." message on my browser.

Can you help me? Thx



Is there any way to define confDirectory for each module, or any way of refer the confDirectory of each module in order to be included in the multi-project?

In fact, what I want is to use the Play.application().configuration() to read the properties defined in "module-application.conf". 


Is there a way to put this in a sbt project, I have something like this





  - web(play)


to run my web app I use play "project web" run but it doesn't work, for some reason the modules inside web (play) are not included when I run it, any ideas?


Trying out the sample and it appears that when executing the play run task on a submodule, it does not load the service*-application.conf. However, I see that you specify the right config in Test. Is there a way to specify the javaOption in "Run" ? Otherwise the submodules do not resolve their independent routers.


@jakubkahovec @stevefturner I guess you can set `javaOptions in run` just like you do `javaOptions in Test` or even both like `javaOptions in (Test, run)` is you would like.


 @Andrew Conner  This is great and works fine in Dev mode. When I run in Prod (play start or play stage and then target/start) only the common url /status works. ServiceA or serviceB urls cannot be found.


Same with dist. I guess thats where you are referring to setting up your own reverse router. Can you please elaborate on that.


 @Andrew Conner Btw, simple to reproduce... checkout the git project... play run work fine.... play start does not.

Andrew Conner
Andrew Conner

 @antonisamy The projects are intended to be run separately, where each names which router it uses (like serviceA.Routes). If you want to run the projects together, just name the combined router by setting the `application.router` setting in your configuration.


@Andrew Conner @antonisamy Andrew, great work on this.  I'm confused by your answer to antonisamy though.  I'm also having trouble running these separately -- i did the following

1) project serviceB

2) stage

3) (exit out of play) ./modules/serviceB/target/start

It runs fine on port 9000, but the only url I can hit is /status.  All other requests (like /serviceB and /serviceB/lottery) return "Action not found" errors

Shawn Liu
Shawn Liu

Very helpful blog. I have a question which is also the problem in my project now. Is it possible to use this approach to package service A & B into different war files using play2war plugin? 


I guess it may be difficult since this approach uses a main project and only has one build script for all sub-projects. 


 @Andrew Conner  did you guys make any headway with Guillaume's suggestion to create an SBT Task to copy application routes into a jar stored in common base Project?


Sub projects are an absolute god send, but the lack of type safety in non-dependent sub project reverse routing is an invitation to runtime errors, driving me nuts -- Play is after all part of TypeSafe ;-)


Do you know if it's possible to modify the routing (in a plugin or the Global object) so that each module can be served through a different domain name? Kinda like Apache's name-based virtual hosting.

Jared Jacobs
Jared Jacobs

Is there really no way to include another project's compiled reverse routes without including the entire project? What's the specific difficulty there? Thanks.