Skip to content

Cannot configure Ebean read replica with Play configuration #566

Closed

Description

@risenhoover

I have been successfully using a read replica with Play Framework 2.7 for years. I am upgrading to Play Framework 2.9 and Ebean 15.1.0 with Play Ebean Plugin 7.3.0.

I have tried two different configurations and with both of them, the default database is recognized and used, but the read replica is not. Here are my two attempts (application.conf):

db.default.driver=org.postgres.Driver
db.default.url='xxxx
db.default.readOnlyUrl='xxx`

db.default.driver=org.postgres.Driver
db.default.url='xxxx

db.readonly.driver=org.postgres.Driver
db.readonly.url='xxxx'
db.readonly.readOnlyDatabase=true

Here is a link to the documentation that shows the 'readOnlyUrl' property in the configuration.
https://github.com/ebean-orm/ebean-datasource/blob/master/ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceConfig.java#L719

Please advise on the proper way to configure a read replica.

Activity

  1. rbygrave commented on Jul 28, 2025

    @rbygrave

    This has been crossed posted, refer to ebean-orm/ebean#3659

  2. risenhoover commented on Jul 29, 2025

    @risenhoover
    Author

    Based on conversations with @rbygrave in the ticket references above, it appears that the play-ebean package does not honor the readonlyUrl configuration item and properly build a read replica. I have reopened this issue since it seems important.

  3. changed the title [-]Cannot configure readonly database with play configuration[/-] [+]Cannot configure Ebean read replica with Play configuration[/+] on Jul 29, 2025
  4. certara-gdoenlen commented on Mar 16, 2026

    @certara-gdoenlen

    @mkurz is this something you could maybe give guidance on? I was hoping to use the readReplica feature for our system.
    @risenhoover did you ever find a solution?

  5. mkurz commented on Oct 8, 2026

    @mkurz
    Member

    This got closed by

    Before it got released, its setting was renamed in

    so with the next releases you configure a read replica like this:

    db.default.url = "jdbc:postgresql://primary-host/app"
    db.replica.url = "jdbc:postgresql://replica-host/app"
    db.replica.hikaricp.readOnly = true
    
    ebean.default = ["models.*"]
    play.ebean.db.default.readOnlyDatasource = "replica"

    The replica is just an additional Play database, so credentials, URL formats like postgres://... and the hikaricp settings work as usual. It becomes the read-only data source of the Ebean server: queries outside of transactions, as well as explicitly read-only transactions (e.g. TxScope.required().setReadOnly(true)), run against the replica, everything else against the primary. Ebean supports one read-only data source per Ebean server, so for multiple replicas use a JDBC URL listing all of them (if the driver supports it, e.g. PostgreSQL's loadBalanceHosts and targetServerType), a load balancer or a reader endpoint.

    Why the attempts above didn't work

    • db.default.readOnlyUrl: that's not a Play setting, so it got silently ignored. Play Ebean only ever handed the main connection pool to Ebean.
    • db.readonly with readOnlyDatabase=true: Play Ebean only creates an Ebean server for databases listed in ebean.*, and readOnlyDatabase is an Ebean setting, not a Play one. Besides, that would be a separate Ebean server, not a read replica used by the default one.
    • readOnlyUrl in Ebean's own properties: Ebean then creates a connection pool of its own for the read-only queries, and copies the user and password from its own main data source configuration. That one is empty with Play Ebean though, as Play provides the main connection pool, so it fails with DataSource user is not set?.
    • The ServerConfigStartup: the NullPointerException comes from the postgres://... URL. Play converts that URL format, but Ebean's DataSourceBuilder needs a JDBC URL (jdbc:postgresql://host:5432/db). The PostgreSQL driver returns no connection for other URLs, which Ebean doesn't expect.

    Until the next release

    With the current releases, either of these works:

    • datasource.default.readOnlyUrl together with datasource.default.username and datasource.default.password in Ebean's own configuration, e.g. conf/application.yaml.
    • A ServerConfigStartup with a JDBC URL and the credentials. It has to be covered by an ebean. config line, e.g. by putting it into the models package, otherwise Ebean doesn't pick it up:
    public class ReadReplicaStartup implements ServerConfigStartup {
      @Override
      public void onStart(DatabaseBuilder config) {
        DataSourceBuilder.Settings replica = DataSourceBuilder.create().settings();
        replica.driver("org.postgresql.Driver");
        replica.url("jdbc:postgresql://replica-host:5432/app");
        replica.username("...");
        replica.password("...");
        config.readOnlyDataSourceBuilder(replica);
      }
    }

    The docs now have a "Using a read replica" section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions