DEV Community

Cover image for I built a production-ready Spring Boot 4 Starter Kit (and Reddit roasted it into something better)
Rahul Kushwaha
Rahul Kushwaha

Posted on

I built a production-ready Spring Boot 4 Starter Kit (and Reddit roasted it into something better)

Why I built this

Every new Spring Boot project starts the same way.

JWT setup. Security config. CORS. Rate limiting.
Docker. CI/CD. Exception handling.

I was copy-pasting the same boilerplate across projects,
so I decided to build it once, do it properly,
and open source it.


What's inside

  • 🔐 JWT Auth — access token (15 min) + refresh token (7 days) with rotation
  • 👮 Role-based access — ROLE_USER, ROLE_ADMIN via @PreAuthorize
  • 🚦 Rate limiting — per IP using Bucket4j
  • 📄 Swagger UI — auto-generated at /swagger-ui.html
  • 🛡️ Global exception handling — consistent ApiResponse on every endpoint
  • 🗃️ Flyway migrations — version-controlled schema
  • 🐳 Docker + Nginx + MySQL — one command deploy
  • ⚙️ GitHub Actions CI/CD — test → build → EC2 deploy
  • 🍪 HTTP-only cookie support — XSS protection

Java 21 + Spring Boot 4


Reddit made it better

I posted on r/SpringBoot and r/java.
The feedback was brutal. And valuable.

Criticism 1:

"Why are you making a DB call on every request?
That defeats the purpose of JWT."

They were right. My JWT filter was loading the user
from DB on every request to get roles.
Completely stateless JWT was the whole point.

Fix: Embedded roles directly into JWT claims at
login time. Filter now extracts roles from token —
zero DB calls per request.

Criticism 2:

"Why not store tokens in HTTP-only cookies?
Bearer headers are XSS vulnerable in browsers."

Also valid. Added HTTP-only cookie support.
Both Bearer header and cookie work simultaneously —
browser apps use cookie, mobile/API clients use header.

Criticism 3:

"Spring Security already handles this with
AbstractAuthenticationProcessingFilter.
You don't need a custom JWT filter."

This one was more nuanced. They suggested
Spring Session + JDBC instead of JWT entirely.

So I added both approaches:

  • main branch → JWT (stateless, mobile-friendly)
  • feature/spring-session → Spring Session JDBC (simpler, instant revocation, survives restarts)

Devs can pick what fits their use case.


How to use it

git clone https://github.com/raahulllkushwaha/springboot-starter-kit
cd springboot-starter-kit

# runs on H2 in-memory — zero setup
mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:8080/swagger-ui.html

Register → Login → copy token → hit protected endpoints.

For production:

cp .env.example .env
# fill your secrets
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Rename for your project

Find & replace com.starterkitcom.yourcompany.app

Then add your entities on top. Auth, Docker,
CI/CD already done.


What I learned

  • Open source feedback > any code review
  • README quality matters more than code quality for adoption
  • JWT stateless = NO DB calls in filter. Period.
  • Spring Security's built-in flow exists for a reason

GitHub:

If this saves you time, a ⭐ means a lot.

Top comments (1)

Collapse
 
nazar_boyko profile image
Nazar Boyko

Embedding the roles into the token is the right fix for the per-request DB hit, and it's worth saying out loud what it quietly trades away. The second roles live inside the JWT, you can't revoke them until it expires, so an admin you demote stays an admin for up to your 15-minute access window. For most apps that's a fine price, and your short access token plus refresh rotation already keeps the window small. The neat part is you basically shipped the escape hatch in the same repo, since the Spring Session branch is exactly what you reach for when you need instant revocation and can live with the session lookup. Letting people pick per use case instead of pretending one model wins is the actually senior move here.