Configuring Gradle and Spring Boot with H2 for local development
Tags: java, spring, gradle, h2
Published: 2021-11-18 14:35:02

If you're anything like me, you ***HATE*** long compilation times. Frequently, we find ourselves in an absurd situation where we discover a new programming language that we love so much, but it also has slower compilation times when compared to its predecessor. Prime examples are Kotlin and TypeScript. It also seems that compilation times are just getting slower, version by version. It's a sad, sad world.

As the famous XKCD comic jokes:

![XKCD Compiling](https://imgs.xkcd.com/comics/compiling.png)

If you're also like me, you absolutely ***LOVE*** good tooling. Good tooling has the potential to make our lives easier, enable us to lose less time waiting or doing empty work. HotSwap for JVM or TypeScript Language Server comes to mind.

## The problem with Spring Boot and databases

There's no such thing as a free lunch. Sure, Spring Boot has awesome tooling, great development experience. But, it is famous for its ***NOTORIOUSLY*** bad start-up time. Some Spring Boot apps take longer to start than my entire OS. It's just hilarious.

Oftentimes, a major contributor to the start-up time is initializing the connection to the database. If you're using Flyway or Liquibase, it is even worse, as it takes time for them to validate your database, or change it if needed.

To waste some more of your precious time, people usually configure their local development environment to use an external database, so you also need to start this as well. Sure, it's good to use the same database for your local development as you do in production, but it's so unnecessary. Configure your integration tests to use that database to check for any potential errors.

Need to modify your database schema? Good luck restarting your DB instance each and every time you make a change. 

## Using H2 in-memory DB for local development with Gradle

The solution to the mentioned problem is to just use an in-memory database for local development. It's going to make your life so much easier.

Let's see how we can configure Gradle to use H2, but only for local development.

As an example, let's say that we have an application with dependencies that look like this, in your `build.gradle`, with PostgreSQL as your production database:

```gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'org.postgresql:postgresql'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
```

You can just add the H2 dependency to this section, but that would mean that in production, your app is going to have the H2 included in it as well. Let's not do that. It's filthy.

By default, the `java` plugin in `build.gradle` [declares two source sets](https://docs.gradle.org/current/userguide/java_plugin.html#source_sets), `main` and `test`.

What we're going to do is add a new `sourceSet` and `configuration` just for local development in `build.gradle`. We can call it `localH2`. You will need to add this piece of code before declaring your dependencies.

```gradle
configurations {
    localH2Implementation.extendsFrom implementation
    localH2RuntimeOnly.extendsFrom runtimeOnly
}

sourceSets {
    localH2 {
        compileClasspath += sourceSets.main.output
        runtimeClasspath += sourceSets.main.output
    }
}
```

This configuration enables us to define dependencies that are specific only to our local environment. But, it includes the whole ***main*** source set, so you'll have all the dependencies that you included normally.

We can now add the H2 dependency, like this:

```gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'org.postgresql:postgresql'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	localH2RuntimeOnly 'com.h2database:h2'
}
```

We're almost there, but now, in our `localH2` source set, we also have the PostgreSQL driver included. To remove that dependency, we can use this block of code:

```gradle
configurations.localH2Implementation {
	exclude group: 'org.postgresql', module: 'postgresql'
}
```

Ah, now everything is so clean.

![OCD](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/all2n1tguty04cudrfrv.jpeg)

## Running a Spring Boot application with the local configuration

We now have two classpaths separated, for the production code and for our local development. But, we haven't explored how we can run this local configuration from your machine. If you just run the application through your IDE or with `./gradlew bootRun`, it's just going to use the production classpath.

If you're using IntelliJ, you'll have to make a small change in your Run Configuration to use the new classpath.

![IntelliJ Run Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0vyt8lvh1o2erag520s9.png)

If you're running your app with `./gradlew bootRun`, don't worry, it's a pretty simple change as well.

You can add a new Gradle task to your `build.gradle` to run it with the new classpath, like so:

```gradle
task localH2(type: org.springframework.boot.gradle.tasks.run.BootRun){
	mainClass = "gradle.springboot.h2.local.example.ExampleApplication"
	classpath = sourceSets.localH2.runtimeClasspath
}
```

The `mainClass` property should contain a reference to your main Java class. You can now run your app by calling `./gradlew localH2`. Isn't it nice?

Even better, having H2 in the classpath configures your ***DataSource*** automatically, so there's no additional configuration to be added.

### Important note

If you had your ***DataSource*** configured in your `application.yml` / `application.properties`, you should pull that config out into a new profile (let's say, `postgres`?), so that it's not loaded by default.

## Final thoughts

Get ready to indulge in the newfound time that you didn't even know you had. Too many times, have we, as developers, had to wait for that slow Spring Boot app to start.

There are at least some ways to make our lives easier and isn't that the whole point of DevOps and the rapid development culture of today?

Be safe!

*The accompanying code can be found at* [the Github Repository](https://github.com/baso53/gradle-springboot-h2-local).