server.port

Sets the HTTP port the embedded server listens on: 8080 by default, 0 for a random free port, -1 to start no server at all.

Signature
server.port=8080
  • Added in Spring Boot Spring Boot 4.1 (verified present)

Parameters

ParameterTypeDescription
$valueoptionalInteger= 8080A port number. 0 asks the operating system for any free port; -1 creates the web application context but never starts the server.

Return value

n/aThe TCP port the embedded web server (Tomcat by default) binds to. The value is read once at startup; changing it later has no effect on a running server.

Errors

Startup fails with 'Port 8080 was already in use' (a PortInUseException) when another process holds the port.

server.port decides which port the embedded server listens on. Without it the application takes 8080, which is fine on a laptop until a second service wants the same port. Startup then stops with Web server failed to start. Port 8080 was already in use.

server.port=8081

Set it from outside the jar

The port is a deployment decision, so it usually comes from the environment rather than from application.properties. Relaxed binding maps the SERVER_PORT environment variable to server.port, and a command-line argument such as --server.port=9090 beats both. Platforms that hand you a port in a variable of their own (often PORT) fit a placeholder with a default:

server.port=${PORT:8080}

The special values

0 asks the operating system for a free port. It is how integration tests avoid clashing when several builds run on one machine: @SpringBootTest(webEnvironment = RANDOM_PORT) sets it for you, and @LocalServerPort injects the number that was picked. Outside tests a random port is rarely what you want, because nothing else knows where to find you.

-1 still builds the full web application context but never opens a socket. It is occasionally useful for a batch job that shares code with a web application, though spring.main.web-application-type=none states that intent more clearly.

Mistakes that show up in production

  • Changing the application port when you meant to move Actuator. management.server.port moves only the operational endpoints, which is the usual way to keep them off the public load balancer.
  • Hard-coding the container port in two places. A Dockerfile EXPOSE, a Kubernetes containerPort and probe definitions all need to agree with the value the application actually uses.
  • Binding to every interface when a sidecar or proxy is the only caller. server.address=127.0.0.1 limits the listener to the local machine.

Inside a container, keep 8080. The container port is private to the container, and the platform maps it to whatever the outside world uses, so there is no reason to vary it per environment.

Example

Example · properties
# Application traffic: the platform may hand us a port in PORT.
server.port=${PORT:8080}

# Only when a sidecar proxy on the same host or pod is the sole caller.
# A platform router outside the container could not reach a loopback listener.
server.address=127.0.0.1

# Actuator on its own port that the public load balancer never routes.
management.server.port=9090

When to use it

  • Running two Spring Boot services side by side on a developer laptop without a port clash
  • Starting each integration test run on a free port so CI agents can run builds in parallel
  • Taking the listening port from a PORT variable provided by a hosting platform

Frequently asked questions

How do I change the port of a Spring Boot application?

Set server.port in application.properties, export SERVER_PORT, or pass --server.port=9090 on the command line. The command line overrides the environment variable, which overrides the properties file.

How do I find out which port was used when server.port is 0?

In tests, inject it with @LocalServerPort. In application code, listen for WebServerInitializedEvent and read event.getWebServer().getPort().

Does server.port also move the Actuator endpoints?

Yes, unless management.server.port is set. Setting management.server.port gives Actuator a separate listener, which you can keep private to the cluster.

More examples

Integration test on a random port

RANDOM_PORT sets server.port=0 for the test, and @LocalServerPort injects the port the operating system actually assigned. Building the client from that number keeps parallel builds on one machine from fighting over 8080.

Example · java
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClient;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class HealthEndpointIT {

    @LocalServerPort
    int port;

    @Test
    void serverAnswersOnTheChosenPort() {
        RestClient client = RestClient.create("http://localhost:" + port);

        ResponseEntity<String> response = client.get()
                .uri("/actuator/health")
                .retrieve()
                .toEntity(String.class);

        assertThat(port).isPositive();
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
}

Logging the port that was actually bound

WebServerInitializedEvent fires once the server is listening, so the port it reports is the real one, even when server.port was 0. Use it to register with a discovery service or to print a URL for local development.

Example · java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class PortAnnouncer {

    private static final Logger log = LoggerFactory.getLogger(PortAnnouncer.class);

    @EventListener
    void onServerStarted(WebServerInitializedEvent event) {
        int port = event.getWebServer().getPort();
        log.info("Accepting HTTP requests on port {}", port);
    }
}

Overriding the port without touching the jar

All three end up as the same property. The command-line argument wins over the environment variable, which wins over application.properties, so a value baked into the jar never stops operations from moving the service.

Example · bash
# Environment variable: relaxed binding maps SERVER_PORT to server.port
SERVER_PORT=9090 java -jar target/orders-0.0.1-SNAPSHOT.jar

# Command-line argument: highest precedence of the usual sources
java -jar target/orders-0.0.1-SNAPSHOT.jar --server.port=9091

# Maven during development
./mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=9092

Discussion

  • Be the first to comment on this lesson.