Accelerating Java Development: A Complete Guide to DevSpace for Local Development

Article

DevSpace is a powerful developer tool for Kubernetes that enables fast, efficient local development by creating a smooth development loop directly in your cluster. For Java developers, DevSpace eliminates the traditional "build, push, deploy" cycle, providing instant code synchronization, hot reloading, and streamlined debugging in a Kubernetes-native environment.

In this guide, we'll explore how to supercharge your Java development workflow with DevSpace, from basic setup to advanced development scenarios.

Why DevSpace for Java Development?

  • Instant Code Synchronization: See changes in seconds without rebuilding containers
  • Hot Reloading: Automatic application restarts on code changes
  • IDE-like Debugging: Direct debugging in Kubernetes pods
  • Consistent Environments: Develop in production-like Kubernetes environments
  • Team Standardization: Share development configurations across teams
  • Multi-Service Development: Work with multiple microservices simultaneously

Part 1: DevSpace Architecture Overview

1.1 How DevSpace Works with Java

Local Java Code → DevSpace Sync → Kubernetes Pod → Running Application
↓               ↓              ↓               ↓
IDE Changes    File Sync      Hot Reload      Instant Feedback
Debugging      Port Forward   Log Streaming   Breakpoints

1.2 Project Structure

java-devspace-app/
├── src/
│   ├── main/java/com/example/
│   └── test/java/com/example/
├── .devspace/
│   ├── devspace.yaml
│   └── commands.yaml
├── charts/
│   └── app/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/
├── Dockerfile
├── Dockerfile.dev
├── devspace-start.sh
└── pom.xml

Part 2: Setup and Configuration

2.1 Installation

macOS:

# Homebrew
brew install devspace
# Or curl
curl -L -o devspace "https://github.com/loft-sh/devspace/releases/latest/download/devspace-darwin-amd64" && sudo install -c -m 0755 devspace /usr/local/bin

Linux:

curl -L -o devspace "https://github.com/loft-sh/devspace/releases/latest/download/devspace-linux-amd64" && sudo install -c -m 0755 devspace /usr/local/bin

Windows:

# Chocolatey
choco install devspace
# Or PowerShell
iwr -useb 'https://github.com/loft-sh/devspace/releases/latest/download/devspace-windows-amd64.exe' -o devspace.exe

2.2 Basic DevSpace Configuration

# .devspace/devspace.yaml
version: v2beta1
name: java-devspace-app
# Variables
vars:
IMAGE_NAME: java-app
REGISTRY: docker.io
REPOSITORY: myorg
JAVA_VERSION: 17
MAVEN_VERSION: 3.8.6
# Docker image building
images:
app:
image: ${REGISTRY}/${REPOSITORY}/${IMAGE_NAME}
tags:
- latest
- ${DEVSPACE_COMMIT}
build:
docker:
dockerfile: ./Dockerfile.dev
context: .
options:
buildArgs:
JAVA_VERSION: ${JAVA_VERSION}
MAVEN_VERSION: ${MAVEN_VERSION}
# Development configuration
dev:
app:
imageSelector: ${images.app.image}
devImage: ${images.app.image}
containers:
- container: app
restartHelper:
enabled: true
path: /restart
# Deployment configuration
deployments:
- name: ${name}
helm:
componentChart: true
values:
containers:
- image: ${images.app.image}
name: app
service:
ports:
- port: 8080
containerPort: 8080
# Development synchronization and port forwarding
profiles:
- name: dev
patches:
- op: add
path: dev.app.containers.0.sync
value:
localSubPath: ./src
containerPath: /app/src
excludePaths:
- "**/target/**"
- "**/.git/**"
- "**/node_modules/**"
- "**/*.class"
- op: add
path: dev.app.containers.0.portForwarding
value:
- port: 5005
remotePort: 5005
- port: 8080
remotePort: 8080
- op: add
path: dev.app.containers.0.logs
value:
enabled: true
lastLines: 100
- name: debug
patches:
- op: add
path: dev.app.containers.0.debug
value:
enabled: true
remoteEnabled: true
# Dependencies (for microservices)
dependencies:
- name: database
source:
git: https://github.com/myorg/devspace-database
subPath: charts/database
# Hooks for automation
hooks:
- command: ./scripts/pre-dev.sh
events:
before: deploy
- command: ./scripts/post-dev.sh
events:
after: deploy

Part 3: Docker Configuration for Development

3.1 Development Dockerfile

# Dockerfile.dev
FROM maven:${MAVEN_VERSION:-3.8.6}-openjdk-${JAVA_VERSION:-17} as dev
# Install additional development tools
RUN apt-get update && apt-get install -y \
curl \
git \
vim \
net-tools \
iputils-ping \
dnsutils \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -r spring && useradd -r -g spring spring
# Set working directory
WORKDIR /app
# Copy Maven files for dependency caching
COPY pom.xml .
COPY .mvn/ .mvn/
COPY mvnw .
# Download dependencies
RUN mvn dependency:go-offline -B
# Copy source code
COPY src ./src
# Create restart trigger file
RUN mkdir -p /restart && touch /restart/.devrestart
# Development environment variables
ENV JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -Dspring.devtools.restart.enabled=true -Dspring.devtools.restart.trigger-file=/restart/.devrestart"
ENV MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m"
# Expose ports
EXPOSE 8080 5005
# Use non-root user
USER spring
# Development entry point
CMD ["mvn", "spring-boot:run", "-Dspring-boot.run.jvmArguments=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"]

3.2 Production Dockerfile

# Dockerfile
# Build stage
FROM maven:3.8.6-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
# Runtime stage
FROM eclipse-temurin:17-jre-jammy
RUN groupadd -r spring && useradd -r -g spring spring
WORKDIR /app
USER spring
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Part 4: Java Application Configuration

4.1 Spring Boot Development Configuration

// File: src/main/java/com/example/DevSpaceApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(DevSpaceProperties.class)
public class DevSpaceApplication {
public static void main(String[] args) {
SpringApplication.run(DevSpaceApplication.class, args);
}
}
// File: src/main/java/com/example/DevSpaceProperties.java
package com.example;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "app.devspace")
public record DevSpaceProperties(
boolean hotReload,
boolean remoteDebug,
int debugPort,
SyncConfig sync,
LoggingConfig logging
) {
public record SyncConfig(
boolean enabled,
String[] excludePatterns,
int pollInterval
) {}
public record LoggingConfig(
boolean devTools,
String level,
boolean showSql
) {}
}

4.2 Development-Specific Configuration

# src/main/resources/application-devspace.yaml
app:
devspace:
hot-reload: true
remote-debug: true
debug-port: 5005
sync:
enabled: true
exclude-patterns: "**/target/**,**/test-output/**,**/.git/**"
poll-interval: 1000
logging:
dev-tools: true
level: DEBUG
show-sql: true
spring:
devtools:
restart:
enabled: true
trigger-file: .devrestart
poll-interval: 1000
quiet-period: 400
livereload:
enabled: true
jackson:
serialization:
indent-output: true
logging:
level:
com.example: DEBUG
org.springframework.web: DEBUG
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
management:
endpoints:
web:
exposure:
include: health,info,metrics,restart
endpoint:
restart:
enabled: true
health:
show-details: always
server:
port: 8080

4.3 Development Controller with Hot Reload Support

// File: src/main/java/com/example/controller/DevSpaceController.java
package com.example.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.core.env.Environment;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Map;
@RestController
@RequestMapping("/api/dev")
public class DevSpaceController {
private static final Logger logger = LoggerFactory.getLogger(DevSpaceController.class);
private final Environment environment;
public DevSpaceController(Environment environment) {
this.environment = environment;
}
@GetMapping("/info")
public ResponseEntity<Map<String, Object>> getDevInfo() {
logger.debug("Development info endpoint called");
return ResponseEntity.ok(Map.of(
"service", "java-devspace-app",
"timestamp", LocalDateTime.now(),
"profiles", environment.getActiveProfiles(),
"hotReload", environment.getProperty("app.devspace.hot-reload", Boolean.class, false),
"remoteDebug", environment.getProperty("app.devspace.remote-debug", Boolean.class, false),
"devTools", environment.getProperty("spring.devtools.restart.enabled", Boolean.class, false)
));
}
@PostMapping("/restart")
public ResponseEntity<Map<String, String>> triggerRestart() {
logger.info("Manual restart triggered via DevSpace endpoint");
// This will trigger Spring Boot DevTools restart
// In a real scenario, you might touch the trigger file
return ResponseEntity.ok(Map.of(
"status", "restart_triggered",
"message", "Application restart has been triggered"
));
}
@GetMapping("/config")
public ResponseEntity<Map<String, Object>> getConfig() {
return ResponseEntity.ok(Map.of(
"java.version", System.getProperty("java.version"),
"user.dir", System.getProperty("user.dir"),
"os.name", System.getProperty("os.name"),
"spring.profiles.active", String.join(",", environment.getActiveProfiles())
));
}
}

Part 5: Advanced DevSpace Configuration

5.1 Multi-Service Development

# .devspace/devspace-multi.yaml
version: v2beta1
name: java-microservices-dev
vars:
REGISTRY: docker.io
REPOSITORY: myorg
images:
user-service:
image: ${REGISTRY}/${REPOSITORY}/user-service
tags: ["latest"]
build:
docker:
dockerfile: ./user-service/Dockerfile.dev
context: ./user-service
order-service:
image: ${REGISTRY}/${REPOSITORY}/order-service
tags: ["latest"]
build:
docker:
dockerfile: ./order-service/Dockerfile.dev
context: ./order-service
api-gateway:
image: ${REGISTRY}/${REPOSITORY}/api-gateway
tags: ["latest"]
build:
docker:
dockerfile: ./api-gateway/Dockerfile.dev
context: ./api-gateway
dev:
user-service:
imageSelector: ${images.user-service.image}
containers:
- container: app
sync:
- localSubPath: ./user-service/src
containerPath: /app/src
excludePaths:
- "**/target/**"
portForwarding:
- port: 8081
remotePort: 8081
- port: 5006
remotePort: 5006
order-service:
imageSelector: ${images.order-service.image}
containers:
- container: app
sync:
- localSubPath: ./order-service/src
containerPath: /app/src
portForwarding:
- port: 8082
remotePort: 8082
- port: 5007
remotePort: 5007
api-gateway:
imageSelector: ${images.api-gateway.image}
containers:
- container: app
sync:
- localSubPath: ./api-gateway/src
containerPath: /app/src
portForwarding:
- port: 8080
remotePort: 8080
- port: 5005
remotePort: 5005
deployments:
- name: user-service
helm:
componentChart: true
values:
containers:
- image: ${images.user-service.image}
service:
ports:
- port: 8081
- name: order-service
helm:
componentChart: true
values:
containers:
- image: ${images.order-service.image}
service:
ports:
- port: 8082
- name: api-gateway
helm:
componentChart: true
values:
containers:
- image: ${images.api-gateway.image}
service:
ports:
- port: 8080
profiles:
- name: with-dependencies
patches:
- op: add
path: dependencies
value:
- name: postgres
source:
git: https://github.com/loft-sh/component-charts
subPath: postgresql
version: 0.1.0
- name: redis
source:
git: https://github.com/loft-sh/component-charts
subPath: redis
version: 0.1.0

5.2 Custom Commands and Scripts

# .devspace/commands.yaml
version: v1beta1
commands:
- name: dev
description: Start development mode with hot reload
command: |-
devspace dev --profile dev
- name: debug
description: Start development with remote debugging
command: |-
devspace dev --profile debug
- name: build
description: Build application image
command: |-
devspace build
- name: deploy
description: Deploy to development namespace
command: |-
devspace deploy --profile dev
- name: logs
description: Show application logs
command: |-
devspace logs -f
- name: test
description: Run tests in development environment
command: |-
devspace enter --container app -- mvn test
- name: integration-test
description: Run integration tests
command: |-
devspace run-pipeline integration-tests
- name: clean
description: Clean development environment
command: |-
devspace purge
kubectl delete pod -l app.kubernetes.io/name=java-devspace-app
- name: restart
description: Restart development container
command: |-
devspace restart
- name: status
description: Show development status
command: |-
echo "=== Development Environment Status ==="
kubectl get pods -l app.kubernetes.io/name=java-devspace-app
echo ""
echo "=== Port Forwarding ==="
kubectl get svc -l app.kubernetes.io/name=java-devspace-app

5.3 Pipeline Configuration

# .devspace/pipelines.yaml
version: v1beta1
pipelines:
dev:
run: |-
devspace build --skip-push
devspace deploy
devspace dev
integration-tests:
run: |-
devspace build --skip-push
devspace deploy
devspace enter --container app -- mvn verify
debug:
run: |-
devspace build --skip-push
devspace deploy
devspace dev --debug
reset:
run: |-
devspace purge
kubectl delete pvc -l app.kubernetes.io/name=java-devspace-app

Part 6: Development Workflows

6.1 Startup Script

#!/bin/bash
# devspace-start.sh
set -e
echo "🚀 Starting Java DevSpace Development Environment"
# Check if DevSpace is installed
if ! command -v devspace &> /dev/null; then
echo "❌ DevSpace is not installed. Please install it first."
echo "   Visit: https://devspace.sh/cli/docs/getting-started/installation"
exit 1
fi
# Check if we have a Kubernetes context
if ! kubectl config current-context &> /dev/null; then
echo "❌ No Kubernetes context found. Please configure kubectl."
exit 1
fi
echo "✅ Kubernetes context: $(kubectl config current-context)"
# Build and start development environment
echo "📦 Building application image..."
devspace build
echo "🚀 Deploying to Kubernetes..."
devspace deploy
echo "🔧 Starting development mode with hot reload..."
devspace dev --profile dev
echo "🎉 Development environment is ready!"
echo "   Application: http://localhost:8080"
echo "   Actuator:    http://localhost:8080/actuator"
echo "   Dev Info:    http://localhost:8080/api/dev/info"

6.2 Development Makefile

# Makefile
.DEFAULT_GOAL := help
.PHONY: help dev debug build deploy test clean logs restart status
help:
@echo "Java DevSpace Development Commands:"
@echo "  make dev       - Start development mode with hot reload"
@echo "  make debug     - Start development with remote debugging"
@echo "  make build     - Build application image"
@echo "  make deploy    - Deploy to development namespace"
@echo "  make test      - Run tests in development environment"
@echo "  make logs      - Show application logs"
@echo "  make restart   - Restart development container"
@echo "  make status    - Show development status"
@echo "  make clean     - Clean development environment"
dev:
./devspace-start.sh
debug:
devspace dev --profile debug
build:
devspace build
deploy:
devspace deploy --profile dev
test:
devspace enter --container app -- mvn test
integration-test:
devspace run-pipeline integration-tests
logs:
devspace logs -f --tail 100
restart:
devspace restart
status:
@echo "=== Development Environment Status ==="
@kubectl get pods -l app.kubernetes.io/name=java-devspace-app
@echo ""
@echo "=== Services ==="
@kubectl get svc -l app.kubernetes.io/name=java-devspace-app
clean:
devspace purge
kubectl delete pod -l app.kubernetes.io/name=java-devspace-app
purge-all:
devspace purge
kubectl delete all -l app.kubernetes.io/name=java-devspace-app
kubectl delete pvc -l app.kubernetes.io/name=java-devspace-app

Part 7: IDE Integration

7.1 VS Code Configuration

// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "DevSpace Remote Debug",
"request": "attach",
"hostName": "localhost",
"port": 5005,
"projectName": "java-devspace-app"
},
{
"type": "java",
"name": "DevSpace Test Debug",
"request": "attach",
"hostName": "localhost",
"port": 5006,
"projectName": "java-devspace-app"
}
]
}
// .vscode/settings.json
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic",
"java.debug.settings.onBuildFailureProceed": true,
"files.watcherExclude": {
"**/target/**": true,
"**/build/**": true
},
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
}

7.2 IntelliJ IDEA Configuration

<!-- .idea/runConfigurations/DevSpace_Remote_Debug.xml -->
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="DevSpace Remote Debug" type="Remote">
<module name="java-devspace-app" />
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
<option name="AUTO_RESTART" value="false" />
<RunnerSettings RunnerId="Debug" />
<ConfigurationWrapper RunnerId="Debug" />
<method v="2" />
</configuration>
</component>

Part 8: Team Development Setup

8.1 Development Environment Bootstrap

# .devspace/team-setup.yaml
version: v2beta1
name: java-team-dev
vars:
NAMESPACE: java-dev-${DEVSPACE_USERNAME}
REGISTRY: docker.io
REPOSITORY: myorg
profiles:
- name: team-dev
patches:
- op: replace
path: deployments.helm.values.labels
value:
app.kubernetes.io/name: ${name}
app.kubernetes.io/instance: ${DEVSPACE_USERNAME}
- op: replace
path: deployments.helm.values.namespace
value: ${NAMESPACE}
- op: add
path: deployments.helm.values.ingress
value:
enabled: true
hosts:
- host: ${DEVSPACE_USERNAME}.dev.mycompany.com
paths:
- path: /
pathType: Prefix
commands:
- name: team-init
description: Initialize team development environment
command: |-
# Create namespace for user
kubectl create namespace ${NAMESPACE} || true
# Set up development context
kubectl config set-context --current --namespace=${NAMESPACE}
# Start development
devspace dev --profile team-dev
- name: team-cleanup
description: Clean up team development environment
command: |-
kubectl delete namespace ${NAMESPACE} || true

8.2 Development Dependencies

# .devspace/dependencies.yaml
version: v2beta1
dependencies:
- name: postgresql
source:
git: https://github.com/bitnami/charts
subPath: bitnami/postgresql
version: 12.0.0
values: |-
auth:
postgresPassword: "devspace123"
database: "java_app"
primary:
persistence:
enabled: false
- name: redis
source:
git: https://github.com/bitnami/charts
subPath: bitnami/redis
version: 17.0.0
values: |-
architecture: standalone
auth:
enabled: false
master:
persistence:
enabled: false
- name: elasticsearch
source:
git: https://github.com/elastic/helm-charts
subPath: elasticsearch
version: 7.17.0
values: |-
replicas: 1
minimumMasterNodes: 1
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi

Part 9: Troubleshooting and Optimization

9.1 Common Issues and Solutions

#!/bin/bash
# scripts/troubleshoot-devspace.sh
echo "🔧 DevSpace Troubleshooting Script"
echo "1. Checking Kubernetes connection..."
kubectl cluster-info
echo "2. Checking current namespace..."
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
echo "3. Checking DevSpace pods..."
kubectl get pods -l app.kubernetes.io/name=java-devspace-app
echo "4. Checking sync status..."
devspace list sync
echo "5. Checking port forwarding..."
devspace list ports
echo "6. Checking logs..."
devspace logs --tail 50
echo "7. Restarting sync..."
devspace sync --restart
echo "✅ Troubleshooting complete"

9.2 Performance Optimization

# .devspace/optimized.yaml
version: v2beta1
name: java-devspace-optimized
profiles:
- name: optimized
patches:
- op: replace
path: images.app.build.docker.options
value:
buildArgs:
JAVA_VERSION: "17"
MAVEN_VERSION: "3.8.6"
target: dev
cacheFrom:
- ${images.app.image}:latest
- op: replace
path: dev.app.containers.0.sync
value:
localSubPath: ./src
containerPath: /app/src
excludePaths:
- "**/target/**"
- "**/test-output/**"
- "**/.git/**"
- "**/node_modules/**"
- "**/*.class"
- "**/*.jar"
- "**/logs/**"
uploadExcludeFile: .dockerignore
poll: false
bandwidthLimits: false
- op: add
path: dev.app.containers.0.resources
value:
limits:
memory: 1Gi
cpu: 500m
requests:
memory: 512Mi
cpu: 100m

Best Practices for DevSpace with Java

  1. Use Development-Specific Dockerfiles: Optimize for fast builds and hot reloading
  2. Leverage Sync Exclusions: Exclude build artifacts and dependencies from sync
  3. Configure Resource Limits: Prevent development containers from consuming too many resources
  4. Use Profiles: Create different profiles for debug, test, and team development
  5. Implement Health Checks: Ensure your application is ready before starting sync
  6. Version Control Configurations: Share DevSpace configurations across the team
  7. Monitor Performance: Use DevSpace analytics to optimize your development loop
  8. Secure Development: Use namespaced development environments for security

Conclusion

DevSpace revolutionizes Java development on Kubernetes by providing a seamless, fast, and efficient development experience. By implementing the patterns and configurations in this guide, you can:

  • Eliminate long build cycles with instant code synchronization
  • Debug applications directly in Kubernetes with full IDE integration
  • Maintain consistent environments across your development team
  • Streamline microservices development with multi-service support
  • Automate development workflows with custom commands and pipelines

The combination of DevSpace's powerful synchronization, Java's robust ecosystem, and Kubernetes' scalability creates an unparalleled development experience that accelerates feature development while maintaining production-like environment fidelity.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper