Why run Spring Boot here?

  • Fixed monthly pricing: no AWS bandwidth surprises or NAT gateway charges. One invoice, same number every month.
  • JVM expertise included: heap sizing, GC tuning, and Actuator monitoring set up from day one. We've run Java in production since 2000.
  • Dutch datacenters: three locations, data stays in the EU. ISO 27001-aligned processes, certification in progress.
  • Direct access to engineers: when your app is leaking memory at 9pm, you talk to the people who run the cluster, not a helpdesk.

Two ways to run your app

Your Spring Boot app is a container or a JAR. Either way, we have a place for it.

Pods CaffeineStacks
What you get A namespace on our managed Kubernetes cluster A dedicated VM with full root access
You deploy with kubectl, Helm, or CI/CD Docker Compose, Ansible, or CI/CD
We handle Cluster, ingress, TLS, monitoring, scaling OS, firewall, backups, monitoring, SSL
Starting at €100/month €250/month
Best for Teams comfortable with kubectl and YAML Teams that want a server they can SSH into

Both options run on the same infrastructure: three Dutch datacenters, private backbone, ISO 27001 certified. The difference is how you interact with it.

JVM in containers: what we've learned

We run Spring Boot apps in production every day. These are the things that matter.

Memory limits

The JVM needs to know it's inside a container. Modern JVMs (17+) detect container limits automatically, but you should still set -XX:MaxRAMPercentage=75. This gives the JVM 75% of the container's memory limit for heap, leaving room for thread stacks, metaspace, and native memory. Without it, your pod gets OOMKilled and you spend an afternoon reading Kubernetes events.

Health checks

Spring Boot Actuator gives you /actuator/health/liveness and /actuator/health/readiness out of the box. These map directly to Kubernetes liveness and readiness probes. Set the initial delay to 30-60 seconds for a typical Spring Boot app. Too low and Kubernetes kills your pod before it finishes starting.

livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  initialDelaySeconds: 45
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 20
  periodSeconds: 5

Garbage collection

G1GC is the default since Java 17 and works well for most Spring Boot apps. If your app serves latency-sensitive APIs, consider ZGC (-XX:+UseZGC) for more predictable pause times. We monitor GC metrics automatically and will flag it if your app spends too much time in GC.

Startup time

A typical Spring Boot app with Spring Data JPA and a few dependencies starts in 5-15 seconds. If yours takes longer, consider lazy initialization (spring.main.lazy-initialization=true) or Spring Boot's CDS support for faster startup. On Pods, slow startup means slow scaling and slow rolling updates.

Database

Most Spring Boot apps need a database. On Pods, you can create a PostgreSQL instance in your namespace using the CloudNativePG operator. Write a manifest, apply it, and you have a managed database with automated backups and failover. MariaDB is also available.

On CaffeineStacks, we set up a dedicated PostgreSQL instance on your VM or on a separate database VM (Cortado, €50/month). We handle backups, updates, and monitoring.

Either way, your application.yml just points to a JDBC URL. No code changes.

Monitoring

Spring Boot Actuator exposes Micrometer metrics that we scrape into Prometheus automatically. You get Grafana dashboards with:

  • JVM metrics: heap usage, GC frequency and pause times, thread count
  • HTTP metrics: request rate, response times, error rates per endpoint
  • Custom metrics: anything you expose via Micrometer shows up automatically
  • Alerts: configurable thresholds to Slack, email, or webhook

No agents to install, no configuration needed. If your app uses Actuator (it probably does), monitoring works out of the box.

Deployment

Build your container image in CI, push to a registry, deploy to your namespace or VM. A typical GitHub Actions workflow:

- name: Build and push
  run: |
    ./mvnw spring-boot:build-image \
      -Dspring-boot.build-image.imageName=registry/my-app:${{ github.sha }}
    docker push registry/my-app:${{ github.sha }}

- name: Deploy
  run: |
    kubectl set image deployment/my-app \
      my-app=registry/my-app:${{ github.sha }}

We help you set up the pipeline during onboarding. If you already have one, we plug into it.

Which option fits your app?

Your situation Our recommendation
One Spring Boot app, comfortable with kubectl Pods Cortado (€100/month) or Espresso (€150/month) if you need a database
Spring Boot app with PostgreSQL, want someone to manage the server CaffeineStacks Espresso (€250/month) + Cortado database (€50/month)
Multiple Spring Boot services, microservices architecture Managed Clusters from €1500/month with dedicated staging and production

What we don't do

We manage infrastructure, not your application code. We won't debug your Spring Boot configuration or write your Dockerfile. But we will tell you when your app is leaking memory, when your connection pool is exhausted, or when your health endpoint is flapping. And if you need hands-on Java expertise, our consulting team can help.

Tell us about your app

Describe what you're running, what you need, and where it lives today. We'll recommend the right setup and give you a clear price. Most teams go from first email to running infrastructure within a week.

Get in touch
CoffeeSprout infrastructure