Building a SaaS Backend in Java in 2026
Spring Boot is unfashionable, which is exactly why it's the right call.
Most YC startups pick Node or Go for the backend. The ones I see hitting Series A and beyond often regret it. Here's the Java stack I'd build a SaaS on today, and why.
It's 2026 and I'm still recommending Spring Boot for most SaaS backends I help architect. This piece explains why, what the modern Java stack actually looks like, and where it's a bad fit.
Why Java in 2026
The honest reasons:
- The tooling is the best in any language. IntelliJ, JFR, async-profiler, JMC, and the JVM ecosystem are decades ahead. When something is slow in production, I find it in 20 minutes on Java. On Node it's often a half day.
- The static type system catches real bugs. With records, sealed types, and pattern matching, modern Java code reads more like Kotlin or Scala than like 2015 Java.
- Long-running services are rock solid. I have JVMs that have run for nine months without a restart, doing real work, with stable memory profiles.
- The talent pool is enormous. Banks, Fortune 500s, and a lot of European tech are Java shops. Hiring is straightforward.
The dishonest reason people avoid Java: status. Java sounds boring. Boring is good when you're shipping a product that needs to work in 2031.
The 2026 stack
Here's what I'd assemble for a new SaaS backend today:
- Java 21 LTS with virtual threads enabled.
- Spring Boot 3.3 as the framework.
- Postgres 16 as the primary store.
- Flyway for migrations.
- jOOQ for the data access layer. I stopped using ORMs.
- Testcontainers for integration tests.
- Resilience4j for circuit breakers and retries.
- Micrometer plus OpenTelemetry for observability.
- GraalVM native image for cold-start sensitive paths only.
Optional but common:
- Kafka if you need real event streaming, otherwise Postgres LISTEN/NOTIFY is fine.
- Redis for caching and rate limiting.
What virtual threads change
Project Loom shipped to LTS in Java 21. The practical impact is that the old async/reactive complexity is gone. You can write synchronous, blocking code and still serve tens of thousands of concurrent connections per server.
I had a service in 2022 written in Spring WebFlux. Reactive types everywhere, hard to debug, cognitive load measured in headaches. In 2024 I rewrote it as plain Spring MVC on virtual threads. Throughput improved by 12%, latency was unchanged, and the codebase was 40% smaller.
If you're starting a new Spring service in 2026 and reaching for WebFlux, I'd ask hard whether you actually need it. The answer is usually no.
The structure I default to
src/main/java/com/example/app/
api/ // controllers, request/response DTOs
domain/ // pure domain logic, no framework imports
persistence/ // jOOQ repositories
events/ // outbox, kafka producers/consumers
config/ // spring config, beans
support/ // cross-cutting helpers
The key rule: domain has no Spring imports. It can be tested with plain JUnit. The API layer translates from HTTP to domain calls. The persistence layer is the only place that knows about Postgres.
This is essentially hexagonal architecture applied modestly. It pays for itself the first time you swap a database or add a new transport.
Where Java is a bad fit
I don't put Java on:
- Edge functions. JVM cold start is too slow. Use TypeScript on Vercel or Cloudflare Workers.
- AI/ML pipelines. The Python ecosystem is just too dominant. Use Python and call it from Java if needed.
- CLI tools. Go ships a single binary. Java doesn't, comfortably.
- Micro-services with extreme cold-start sensitivity. Native image helps, but it's still operationally painful. Pick another runtime.
The startup objection
"But Spring Boot is heavy."
Heavy compared to what? A Hello World in Spring Boot starts in 1.5 seconds and uses 200MB. By the time you've added an ORM, a queue, a logger, and an HTTP client to your Express app, you're not far off.
The marginal cost of Spring's "weight" is rounding error. The marginal benefit of its ecosystem, type system, and tooling is enormous when you're three years into the codebase.
The sharper insight
Most teams that pick a "fast" stack for the wrong reason end up rewriting it. I have watched four Node startups in five years rewrite their backend in Java or Go because the original codebase had become unmaintainable. None of them rewrote because they had hit a performance wall. They rewrote because they couldn't safely change the code anymore.
If you're building something you intend to maintain for a decade, pick a language that is good at being maintained for a decade. Java is excellent at that. Pick the unfashionable thing and ship.
If you'd like help architecting a Java SaaS backend, I do this exact work as part of a build engagement.