§What’s new in Play 2.4

This page highlights the new features of Play 2.4. If you want learn about the changes you need to make to migrate to Play 2.4, check out the Play 2.4 Migration Guide.

§Dependency Injection

Play now supports dependency injection out of the box.


A long term strategy for Play is to remove Play’s dependence on global state. Play currently stores a reference to the current application in a static variable, and then uses this variable in many places throughout its codebase. Removing this has the following advantages:

Removing Play’s global state is however a big task that will require some disruptive changes to the way Play applications are written. The approach we are taking to do this is to do as much as possible in Play 2.4 while maintaining backwards compatibility. For a time, many of Play’s APIs will support both methods that rely on require global state and methods that don’t rely on global state, allowing you to migrate your application to not depend on global state incrementally, rather than all at once when you uprgade to Play 2.4.

The first step to removing global state is to make it such that Play components have their dependencies provided to them, rather than looking them up statically. This means providing out of the box support for dependency injection.


In the Java ecosystem, the approach to dependency injection is generally well agreed upon in JSR 330, but the right implementation is widely debated, with many existing competing implementations such as Guice, Spring and JEE itself.

In the Scala ecosystem, the approach to dependency injection is not generally agreed upon, with many competing compile time and runtime dependency injection approaches out there.

Play’s philosophy in providing a dependency injection solution is to be unopinionated in what approaches we allow, but to be opinionated to the approach that we document and provide out of the box. For this reason, we have provided the following:

You can read more about Play’s dependency injection support for Java and Scala.


One of the biggest advantages of introducing dependency injection to Play is that many parts of Play can now be much easier to test. Play now provides a number of APIs to assist in mocking and overriding components, as well as being able to test interactions with Play components in isolation from the rest of your Play application.

You can read about these new APIs here:

§Embedding Play

It is now straightforward to embed a Play application. Play 2.4 provides both APIs to start and stop a Play server, as well as routing DSLs for Java and Scala so that routes can be embedded directly in code.

In Java, see Embedding Play as well as information about the Routing DSL.

In Scala, see Embedding Play as well as information about the String Interpolating Routing DSL.

§Aggregated reverse routers

Play now supports aggregating reverse routers from multiple sub projects into a single shared project, with no dependency on the project the routes files came from. This allows a modular Play application to use the Play reverse router as an API between modules, allowing them to render URLs to each other without depending on each other. It also means a dependency free reverse router could be extracted out of a Play project, and published, for use by external projects that invoke the APIs provided by the project.

For details on how to configure this, see Aggregating Reverse Routers.

§Java 8 support

Play 2.4 now requires JDK 8. Due to this, Play can, out of the box, provide support for Java 8 data types. For example, Play’s JSON APIs now support Java 8 temporal types including Instance, LocalDateTime and LocalDate.

The Play documentation now shows code examples using Java 8 syntax for anonymous inner classes. As an example, here’s how some of the code samples have changed:


return promise(new Function0<Integer>() {
  public Integer apply() {
    return longComputation();
 }).map(new Function<Integer,Result>() {
  public Result apply(Integer i) {
    return ok("Got " + i);


return promise(() -> longComputation())
  .map((Integer i) -> ok("Got " + i));

§Maven/sbt standard layout

Play will now let you use either its default layout or the directory layout that is the default for Maven and SBT projects. See the Anatomy of a Play application page for more details.


Anorm has been extracted into a separate project with its own lifecycle, allowing anorm to move at its own pace, not bound to Play. The anorm project can be found here.

New features in anorm include:


Play’s Ebean support has been extracted into a separate project with its own lifecycle, allowing Ebean support to move at its own pace, not bound to Play. The play-ebean project can be found here.

play-ebean now supports Ebean 4.x.


HikariCP is now the default JDBC connection pool. Its properties can be directly configured using .conf files and you should rename the configuration properties to match what is expected by HikariCP.


WS now supports Server Name Indication (SNI) in HTTPS – this solves a number of problems with HTTPS based CDNs such as Cloudflare which depend heavily on SNI.

§Experimental Features

Play provides two new experimental features. These are labelled as experimental because the APIs for them have not yet been finalised, and may change from one release to the next. Binary compatibility is not guaranteed on these APIs.

§Akka HTTP support

Play supports a new Akka HTTP backend, as an alternative to the current Netty backend. For instructions on using it, see Akka Http Server.

§Reactive Streams Support

Play provides an iteratees based implementation of Reactive Streams, allowing other Reactive Streams implementations, such as Akka Streams or RxJava, to be used with Play’s iteratee IO APIs. For more information, see Reactive Streams Integration.

Next: Migration Guides

Found an error in this documentation? The source code for this page can be found here. After reading the documentation guidelines, please feel free to contribute a pull request.