Database migrations with R2DBC

Steve's answer is correct hat R2DBC is primarily about interaction with the actual data. I'd like to add a different perspective.

It's true that a reactive API does not provide any improvement during migrations. In fact, looking closely, migrations are part of the startup process which is typically synchronous, at least synchronized to some extent.

Requiring JDBC for migration adds to complexity in such an application arrangement. You are required to include a JDBC driver to an existing R2DBC setup and you need to configure another database connection that points to the same database as with R2DBC. Both requirements are error-prone as they need to be configured to do the exact same thing.

Nowadays, application configuration frameworks (Spring Boot, Micronaut, Quarkus) activate functionality when a certain library is available from the classpath. Having a JDBC driver configured boots functionality that isn't required for the application but required during bootstrapping and that is sort of a waste of resources.

Ideally, you configure a single database connection technology that is reused for schema migration and for later data interaction within your application.

Therefore it makes sense to ask Liquibase and Flyway to provide an R2DBC-based integration.


You can try my package r2dbc-migrate.

In minimal configuration (let's suppose that you are using Spring Boot 2.3.0.M3), just add

<dependency>
  <groupId>name.nkonev.r2dbc-migrate</groupId>
  <artifactId>r2dbc-migrate-spring-boot-starter</artifactId>
  <version>0.0.24</version>
</dependency>

to pom.xml

then add .sql files in classpath, for example in /db/migration/

then add

r2dbc.migrate.resourcesPath: classpath:/db/migration/*.sql

to your application.yml


It doesn't seem to me (from an admittedly cursory glance at the front page of the R2DBC web page) that the goals of R2DBC really have anything to do with migrations. That page lists key features as:

  • Reactive Streams - R2DBC is founded on Reactive Streams providing a fully reactive non-blocking API.
  • Relational Databases - R2DBC engages SQL databases with a reactive API, something not possible with the blocking nature of JDBC.
  • Scalable Solutions - Reactive Streams makes it possible to move from the classic one thread per connection approach to a more powerful, more scalable approach.

There is nothing in there that warrants adding R2DBC support to a framework like Liquibase. The JDBC drivers currently in use don't suffer from their use of a non-blocking API, don't really need a "reactive API", and almost certainly don't need to have more than one thread per connection.

Migration tools are primarily concerned with the shape/structure of the database and not the contents, while R2DBC is aimed at applications that primarily care about the actual data.

In Summary, I don't see any reason why someone wouldn't use a migration tool like Liquibase that uses JDBC just because their application uses R2DBC, and I don't see any advantage to adding R2DBC support to a tool like Liquibase.