# tut-spring-boot-kotlin walks through building a blog with Spring Boot and Kotlin

> This Spring guide is a tutorial rather than a framework: it builds a sample blog application with Spring Boot, Kotlin, Mustache, Spring Data JDBC and H2, and it spends most of its length on the two build-tool details that trip up Kotlin newcomers. The value is the build configuration, not the blog.

**spring-guides/tut-spring-boot-kotlin** — Building web applications with Spring Boot and Kotlin :: Learn how to easily build and test web applications with Spring, Kotlin, Junit and JDBC

- Repository: https://github.com/spring-guides/tut-spring-boot-kotlin
- Website: https://spring.io/guides/tutorials/spring-boot-kotlin/
- Stars: 978 · Forks: 301
- Language: Kotlin
- License: not declared
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/spring-guides-tut-spring-boot-kotlin

## A tutorial whose real subject is the build file

The stated goal is to efficiently build a sample blog application by combining Spring Boot and Kotlin. The description adds the testing and persistence tools: Spring, Kotlin, JUnit and JDBC. So the artefact is a worked example, and the blog is the excuse.

What makes the guide more than a copy-paste walkthrough is where it spends its attention. A large share of the text is about two things that a Java developer arriving in Kotlin will get wrong: the `kotlin-spring` compiler plugin, which exists because Kotlin classes are final by default and Spring needs to proxy them, and the JSpecify nullability annotations that Spring now puts on its own Java APIs. Neither of those is visible in application code, and both cause confusing failures if they are missing.

The repository layout confirms it is a guide project rather than a reusable library. Alongside the README in AsciiDoc format there is a `build.gradle.kts`, a `pom.xml`, `settings.gradle.kts`, Gradle and Maven wrapper scripts, `src/` and `test/` directories, and a `.mvn/` directory for the Maven wrapper. There is no packaging descriptor for a library and no published artefact.

The repository has no GitHub releases, and the last push was on 2026-09-01. The guide is published through the Spring guides site rather than through this repository, which is where the link in the project metadata points.

## Three ways to generate the project, one dependency list

The guide covers project creation three times over, because different readers arrive differently.

The web route is start.spring.io, where you pick the Kotlin language, which also applies to IntelliJ IDEA Ultimate through File, New, Project, Spring Initializr. The command line route uses the Initializr HTTP API with curl on a Unix-like system:

```bash
$ mkdir blog && cd blog
$ curl https://start.spring.io/starter.zip -d language=kotlin -d type=gradle-project-kotlin -d dependencies=web,mustache,jdbc,h2,devtools -d packageName=com.example.blog -d name=Blog -o blog.zip
```

One flag is worth noting separately: adding `-d type=gradle-project` gives you plain Gradle rather than the Kotlin DSL variant. The guide treats Gradle with the Kotlin DSL as the recommended choice because that is the default when generating a Kotlin project, while leaving Maven open for readers who prefer it.

The dependency list is identical across all three routes: Spring Web, Mustache, Spring Data JDBC, H2 Database and Spring Boot DevTools. Spring Web for the HTTP layer, Mustache for the templates, Spring Data JDBC rather than JPA, an in-memory H2 database so nothing needs installing, and DevTools for restart during development.

The guide also warns about a small practical detail. The generated zip contains a standard project in the root directory, so you may want to create an empty directory before unpacking it.

## Why the kotlin-spring plugin is not optional

Kotlin makes classes and methods final by default, unlike Java, where they are open unless marked otherwise. Spring's proxy-based machinery, CGLIB in particular, needs to subclass your classes in order to wrap their methods with transaction handling, caching and similar behaviour. Without help, that subclassing fails at runtime with a confusing error.

The `kotlin-spring` plugin solves it by automatically opening classes and methods that are annotated, or meta-annotated, with Spring annotations. The guide explains the consequence directly: you can create `@Configuration` or `@Transactional` beans without adding the `open` qualifier that CGLIB proxies would otherwise require.

Two other compiler settings are configured in the same place, and they are the ones most often missed. Strict interpretation of JSR 305 annotations is enabled for libraries that use them, and defaults when no use-site targets are specified are configured as well, which maps annotation defaults onto parameters and properties in the way Spring expects.

The Gradle build file shows the whole configuration in one place:

```kotlin
plugins {
    id("org.springframework.boot") version "4.0.1"
    id("io.spring.dependency-management") version "1.1.7"
    kotlin("jvm") version "2.2.21"
    kotlin("plugin.spring") version "2.2.21"
}

kotlin {
    compilerOptions {
        freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
    }
}
```

Note the two Kotlin plugins carrying the same version. `plugin.spring` is the all-open plugin, and it must be kept in step with the Kotlin compiler version it was built against.

## Null safety on both sides of the Java boundary

Kotlin's null safety is treated as a headline feature, and the guide spends a paragraph on why it matters: nullability is settled at compile time instead of surfacing as a NullPointerException at runtime, and the value-or-no-value semantics come without wrapper types like `Optional`.

The more interesting half of the argument is about Java code, not Kotlin code. Spring cannot put Kotlin's type system on its own Java APIs, so it expresses null safety through tooling-friendly JSpecify annotations on those APIs instead. Kotlin translates JSpecify annotations on Java APIs into Kotlin nullability out of the box, which is what makes a Spring Java API usable from Kotlin without the usual defensive wrapping.

That translation is not free of configuration. JSpecify annotations are only visible to the Kotlin compiler if JSR 305 annotations are interpreted strictly, which is what the `-Xjsr305=strict` compiler argument in the Gradle build does. The `-Xannotation-default-target=param-property` argument handles the other half, making an annotation without an explicit use-site target apply to the right place.

The practical upshot is that a Kotlin Spring project that omits those two flags will not fail loudly. It will compile, and the nullability information coming across from Spring's Java APIs will be weaker than it should be, so mistakes that the type system could have caught will surface later.

## Maven needs the same plugin by a different route

Readers who prefer Maven are not left to work it out, because the guide includes the equivalent `pom.xml` fragment. The Maven side has to point the compiler at the Kotlin source directories, since Maven's defaults assume `src/main/java`, and it has to register the all-open compiler plugin explicitly, because Maven has no equivalent of the Gradle plugin block.

The `sourceDirectory` and `testSourceDirectory` are redirected to `src/main/kotlin` and `src/test/kotlin`. The `kotlin-maven-plugin` configuration carries the same two arguments as the Gradle build, `-Xjsr305=strict` and `-Xannotation-default-target=param-property`, and lists the `spring` compiler plugin. It also pulls in `kotlin-maven-allopen` as a dependency of the plugin, using the Kotlin version property.

Two things stand out. The compiler arguments are identical to the Gradle ones, which is the point: the semantics of the application should not depend on the build tool. And the all-open behaviour arrives through a Maven-specific artifact, `kotlin-maven-allopen`, rather than through a plugin declaration, which is exactly the kind of asymmetry that gets missed when a team switches build tools halfway through a project.

The `spring-boot-maven-plugin` is also declared, as you would expect in a Spring Boot Maven project.

## Two licence files and no releases

The licence situation here is unusual and worth reading rather than assuming. The repository root carries two licence files with distinct names, `LICENSE.code.txt` and `LICENSE.writing.txt`, and the project metadata lists the licence as unknown, which reflects that there is no single `LICENSE` file to point at.

The two-file arrangement follows a pattern used by documentation and tutorial repositories: one licence governs the source code in the repository, and a separate one governs the prose. The Spring guides project publishes these under different terms because a guide's written content and its sample code are treated as different artefacts, and the sample code is meant to be copied into projects that are not themselves copyleft.

If you plan to reuse the sample code, read `LICENSE.code.txt` for the terms that apply to it, and treat the writing licence as applying to the prose rather than the code. That is a description of the file layout, not legal advice, and the files themselves are the authority.

On maintenance, the picture is thin by design. There are no GitHub releases, so there is no version history to pin and no changelog to read. The last push was on 2026-09-01, and the guide tracks the Spring Boot and Kotlin versions current at the time it was written, which is visible in the plugin versions in the build file.

## Where this guide stops and the reference docs begin

The honest limit of this repository is that it is not a substitute for either the Spring Framework reference documentation or the Spring Boot reference documentation. The guide says so, and points to both, alongside the Kotlin tour for the language itself and the Spring Framework reference for Kotlin code samples.

The alternative to learning from this guide is to learn from the reference documentation directly. The difference in approach is what each is optimised for. The reference documentation describes the whole framework exhaustively, which is what you want when you need the exact behaviour of a specific annotation. The guide narrows to one working application and explains the handful of decisions you have to get right to build it, which is what you want when the build fails and you do not yet know why.

For getting help, the guide names two concrete places: the `spring` and `kotlin` tags on Stack Overflow, and the `#spring` channel on Kotlin Slack. Both are more useful than a general search, because a question tagged for both frameworks is more likely to reach someone who has already hit the same Kotlin-specific Spring issue.

One more alternative is worth naming for teams that already know Java and Spring. If the goal is the application rather than the Kotlin specifics, the same blog application can be built in Java, and the Kotlin-specific decisions in this guide become optional rather than required. That is a reasonable choice for a mixed-language team, and a poor one if the point of the exercise is to learn the Kotlin integration.

## Conclusion

Read this guide when you are setting up a Spring Boot project in Kotlin and want the kotlin-spring plugin, the JSR 305 strict compiler flags and the Java source directory layout explained rather than assumed. Do not adopt it as a project template or as a framework reference, since it contains no application code you would base a service on, it publishes no releases, and the repository carries no licence file that the project metadata could identify. Before copying anything from it, check that your own `build.gradle.kts` declares `kotlin("plugin.spring")` alongside `kotlin("jvm")`, confirm the `freeCompilerArgs` entry with `-Xjsr305=strict` and `-Xannotation-default-target=param-property` is present in your build, and decide whether you want the Gradle Kotlin DSL or the Maven route, since the two files configure the same plugin differently.

## FAQ

### How do I create a Spring Boot Kotlin project from the command line?

The guide uses the Initializr HTTP API with curl: `mkdir blog && cd blog` then a curl request to start.spring.io/starter.zip with `language=kotlin` and `type=gradle-project-kotlin`, plus the dependencies web, mustache, jdbc, h2 and devtools. Adding `-d type=gradle-project` selects plain Gradle instead of the Kotlin DSL.

### Why does a Spring Boot Kotlin project need the kotlin-spring plugin?

Kotlin classes and methods are final by default, and Spring's CGLIB proxies need to subclass them, for example for `@Configuration` or `@Transactional` beans. The `kotlin-spring` plugin automatically opens classes and methods annotated with Spring annotations, removing the need to add the `open` qualifier by hand.

### What do the -Xjsr305=strict and -Xannotation-default-target=param-property flags do?

Strict interpretation of JSR 305 annotations makes the JSpecify nullability annotations Spring puts on its Java APIs visible to the Kotlin compiler, and the annotation-default-target setting defines what happens when an annotation has no use-site target. Both are added through `freeCompilerArgs` in the Kotlin compiler options.

### Which dependencies does the tutorial blog application use?

The dependency list is Spring Web, Mustache, Spring Data JDBC, H2 Database and Spring Boot DevTools, the same set whether you generate the project from start.spring.io, from the command line or through IntelliJ IDEA.

### Can the tut-spring-boot-kotlin guide be used with Maven instead of Gradle?

Yes. The guide includes a `pom.xml` fragment that redirects `sourceDirectory` and `testSourceDirectory` to the Kotlin source directories, passes the same two compiler arguments, and adds the `kotlin-maven-allopen` dependency so the spring compiler plugin opens classes the same way.

## Sources

- [Issues](https://github.com/spring-guides/tut-spring-boot-kotlin/issues)
- [Project website](https://spring.io/guides/tutorials/spring-boot-kotlin/)
- [README](https://github.com/spring-guides/tut-spring-boot-kotlin/blob/main/README.md)
- [spring-guides/tut-spring-boot-kotlin on GitHub](https://github.com/spring-guides/tut-spring-boot-kotlin)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/spring-guides-tut-spring-boot-kotlin
