Close

Spring Boot - Serving static web content

[Last Updated: Nov 15, 2026]

Static content means files that the server sends as they are, for example HTML pages, CSS files, JavaScript files and images. Spring Boot can serve these files without any controller code.

By default, Spring Boot looks for static content in the following locations on the classpath. If the same file name exists in more than one location, the first location in this list wins:

  1. /META-INF/resources
  2. /resources
  3. /static
  4. /public

Most projects simply use /static.


Example

Project setup

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.2</version>
  </parent>
  <groupId>com.logicbig.example</groupId>
  <artifactId>boot-serving-static-pages</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <java.version>25</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
</project>
plugins {
    java
    id("org.springframework.boot") version "4.1.2"
    id("io.spring.dependency-management") version "1.1.7"
}

println(">>> EXECUTING SCRIPT: build.gradle.kts (Kotlin DSL)")

group = "com.logicbig.example"
version = "1.0-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_25
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
}
plugins {
    id 'java'
    id 'org.springframework.boot' version '4.1.2'
    id 'io.spring.dependency-management' version '1.1.7'
}

println ">>> EXECUTING SCRIPT: build.gradle (Groovy DSL)"

group = 'com.logicbig.example'
version = '1.0-SNAPSHOT'

java {
    sourceCompatibility = JavaVersion.VERSION_25
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

Creating static pages

Let's create a static web page in one of the locations stated above

src/main/resources/static/page1.html

<h2>Page 1</h2>

We do not need a controller for static content.

Main class

package com.logicbig.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

@EnableAutoConfiguration
public class WebStaticPagesExample {

    public static void main(String[] args) {
        SpringApplication app =
                new SpringApplication(WebStaticPagesExample.class);
        app.run(args);
    }
}

Output


. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v4.1.2)

2026-11-15T08:13:25.851-06:00 INFO 24252 --- [ main] c.l.example.WebStaticPagesExample : Starting WebStaticPagesExample using Java 25 with PID 24252 (D:\LogicBig\example-projects\spring-boot\boot-serving-static-pages\target\classes started by joe2 in D:\LogicBig\example-projects\spring-boot\boot-serving-static-pages)
2026-11-15T08:13:25.855-06:00 INFO 24252 --- [ main] c.l.example.WebStaticPagesExample : No active profile set, falling back to 1 default profile: "default"
2026-11-15T08:13:26.404-06:00 INFO 24252 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2026-11-15T08:13:26.415-06:00 INFO 24252 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-11-15T08:13:26.416-06:00 INFO 24252 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.27]
2026-11-15T08:13:26.456-06:00 INFO 24252 --- [ main] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 580 ms
2026-11-15T08:13:26.530-06:00 INFO 24252 --- [ main] o.s.b.w.a.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
2026-11-15T08:13:26.688-06:00 INFO 24252 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-11-15T08:13:26.692-06:00 INFO 24252 --- [ main] c.l.example.WebStaticPagesExample : Started WebStaticPagesExample in 1.113 seconds (process running for 1.348)

In above example, we ran the main class directly from IntelliJ IDEA. Alternatively, you can execute it from the command line using your build tool:

  • Maven: mvn spring-boot:run
  • Gradle: gradle bootRun

Accessing the page at 'http://localhost:8080/page1.html':


Output
$ curl -s "http://localhost:8080/page1.html"
<h2>Page 1</h2>

Pages for the other locations are in the project browser below. Please try them one by one.

Tip: If your application is packaged as a jar file, do not use the src/main/webapp folder. Build tools ignore it for jar files. Use one of the classpath locations listed above instead.



Setting custom locations

We can change the static locations with the spring.web.resources.static-locations property. The new list replaces the default locations.


Example

package com.logicbig.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import java.util.Properties;

@EnableAutoConfiguration
public class ReplaceDefaultLocationsExample {

    public static void main(String[] args) {

        SpringApplication app = new SpringApplication(
                ReplaceDefaultLocationsExample.class);

        Properties properties = new Properties();
        properties.setProperty("spring.web.resources.static-locations",
                               "classpath:/newLocation1/, "
                                       + "classpath:/newLocation2/");
        app.setDefaultProperties(properties);
        app.run(args);
    }
}

In Spring Boot 2.3 and older, the property was named spring.resources.static-locations. Spring Boot 2.4 deprecated it in favor of spring.web.resources.static-locations, and the old name no longer works from 2.6.0.

In a normal project, you would put the same setting in application.properties:

spring.web.resources.static-locations=classpath:/newLocation1/, classpath:/newLocation2/

Or in application.yml:

spring:
  web:
    resources:
      static-locations:
        - classpath:/newLocation1/
        - classpath:/newLocation2/

The property spring.web.resources.static-locations (dash notation) can also be written as spring.web.resources.staticLocations (camel case) or spring.web.resources.static_locations (underscore). This works because of Spring Boot's relaxed binding rules. Spring Boot applies these rules when it maps properties to a class annotated with @ConfigurationProperties (see this tutorial). Here, the properties are mapped to WebProperties.Resources, a Spring Boot class with the prefix spring.web.resources. The static locations value is set through its setStaticLocations() method. The dash notation is the recommended style.

To test this, add new page in the new locations:

src/main/resources/newLocation1/Page5.html

<h2>Page 5 at newLocation1</h2>

src/main/resources/newLocation2/Page6.html

<h2>Page 6 at newLocation2</h2>

Note that URLs are case-sensitive on most servers, so use exactly 'Page5.html' in the browser.

Run the main class ReplaceDefaultLocationsExample then access the new pages in browser and curl:


Output
$ curl -s "http://localhost:8080/page5.html"
<h2>Page 5 at newLocation1</h2>



Output
$ curl -s "http://localhost:8080/page6.html"
<h2>Page 6 at newLocation2</h2>

Adding locations for static content via WebMvcConfigurer

We can add more static locations by implementing the WebMvcConfigurer interface and overriding its addResourceHandlers method.

This does not replace the default locations. The default handler for '/**' still works.

package com.logicbig.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableAutoConfiguration
public class AddCustomLocations {
    @Bean
    WebMvcConfigurer configurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addResourceHandlers(
                    ResourceHandlerRegistry registry) {
                registry.addResourceHandler("/pages/**")
                        .addResourceLocations("classpath:/my-custom-location/");
            }
        };
    }

    public static void main(String[] args) {

        SpringApplication app =
                new SpringApplication(AddCustomLocations.class);
        app.run(args);
    }
}

Add a new page: src/main/resources/my-custom-location/page7.html

src/main/resources/my-custom-location/page7.html

<h2>Page 7 at custom location</h2>

Run the class AddCustomLocations and open the page at http://localhost:8080/pages/page7.html


Output
$ curl -s "http://localhost:8080/pages/page7.html"
<h2>Page 7 at custom location</h2>

Changing the URL pattern

By default, static files are served from the root of the URL ('/**'). To serve them under a prefix, use the spring.mvc.static-path-pattern property:

spring.mvc.static-path-pattern=/resources/**

Now 'page1.html' is available at 'http://localhost:8080/resources/page1.html'.


Static welcome page

A static welcome page is a file named 'index.html' placed in any of the active static locations. Spring Boot shows it when the user opens the root URL ('/'). If there is no 'index.html', Spring Boot looks for a template named 'index' instead (if you use a template engine).

For example, let's add the following index.html and run our first example class, WebStaticPagesExample.

src\main\resources\static\index.html

<h2>Welcome Page</h2>

Output
$ curl -s "http://localhost:8080"
<h2>Welcome Page</h2>

Example Project

Dependencies and Technologies Used:

  • Spring Boot 4.1.2
    Corresponding Spring Framework Version 7.0.10
     Version Compatibility: 2.0.0.RELEASE - 4.1.2Version List
    ×

    Version compatibilities of spring-boot-starter-parent with this example:

    • 2.0.0.RELEASE
    • 2.0.1.RELEASE
    • 2.0.2.RELEASE
    • 2.0.3.RELEASE
    • 2.0.4.RELEASE
    • 2.0.5.RELEASE
    • 2.0.6.RELEASE
    • 2.0.7.RELEASE
    • 2.0.8.RELEASE
    • 2.0.9.RELEASE
    • 2.1.0.RELEASE
    • 2.1.1.RELEASE
    • 2.1.2.RELEASE
    • 2.1.3.RELEASE
    • 2.1.4.RELEASE
    • 2.1.5.RELEASE
    • 2.1.6.RELEASE
    • 2.1.7.RELEASE
    • 2.1.8.RELEASE
    • 2.1.9.RELEASE
    • 2.1.10.RELEASE
    • 2.1.11.RELEASE
    • 2.1.12.RELEASE
    • 2.1.13.RELEASE
    • 2.1.14.RELEASE
    • 2.1.15.RELEASE
    • 2.1.16.RELEASE
    • 2.1.17.RELEASE
    • 2.1.18.RELEASE
    • 2.2.0.RELEASE
    • 2.2.1.RELEASE
    • 2.2.2.RELEASE
    • 2.2.3.RELEASE
    • 2.2.4.RELEASE
    • 2.2.5.RELEASE
    • 2.2.6.RELEASE
    • 2.2.7.RELEASE
    • 2.2.8.RELEASE
    • 2.2.9.RELEASE
    • 2.2.10.RELEASE
    • 2.2.11.RELEASE
    • 2.2.12.RELEASE
    • 2.2.13.RELEASE
    • 2.3.0.RELEASE
    • 2.3.1.RELEASE
    • 2.3.2.RELEASE
    • 2.3.3.RELEASE
    • 2.3.4.RELEASE
    • 2.3.5.RELEASE
    • 2.3.6.RELEASE
    • 2.3.7.RELEASE
    • 2.3.8.RELEASE
    • 2.3.9.RELEASE
    • 2.3.10.RELEASE
    • 2.3.11.RELEASE
    • 2.3.12.RELEASE
    • 2.4.0
    • 2.4.1
    • 2.4.2
    • 2.4.3
    • 2.4.4
    • 2.4.5
    • 2.4.6
    • 2.4.7
    • 2.4.8
    • 2.4.9
    • 2.4.10
    • 2.4.11
    • 2.4.12
    • 2.4.13
    • 2.5.0
    • 2.5.1
    • 2.5.2
    • 2.5.3
    • 2.5.4
    • 2.5.5
    • 2.5.6
    • 2.5.7
    • 2.5.8
    • 2.5.9
    • 2.5.10
    • 2.5.11
    • 2.5.12
    • 2.5.13
    • 2.5.14
    • 2.5.15
    • 2.6.0
    • 2.6.1
    • 2.6.2
    • 2.6.3
    • 2.6.4
    • 2.6.5
    • 2.6.6
    • 2.6.7
    • 2.6.8
    • 2.6.9
    • 2.6.10
    • 2.6.11
    • 2.6.12
    • 2.6.13
    • 2.6.14
    • 2.6.15
    • 2.7.0
    • 2.7.1
    • 2.7.2
    • 2.7.3
    • 2.7.4
    • 2.7.5
    • 2.7.6
    • 2.7.7
    • 2.7.8
    • 2.7.9
    • 2.7.10
    • 2.7.11
    • 2.7.12
    • 2.7.13
    • 2.7.14
    • 2.7.15
    • 2.7.16
    • 2.7.17
    • 2.7.18
    • Java 17 min
    • 3.0.0
    • 3.0.1
    • 3.0.2
    • 3.0.3
    • 3.0.4
    • 3.0.5
    • 3.0.6
    • 3.0.7
    • 3.0.8
    • 3.0.9
    • 3.0.10
    • 3.0.11
    • 3.0.12
    • 3.0.13
    • 3.1.0
    • 3.1.1
    • 3.1.2
    • 3.1.3
    • 3.1.4
    • 3.1.5
    • 3.1.6
    • 3.1.7
    • 3.1.8
    • 3.1.9
    • 3.1.10
    • 3.1.11
    • 3.1.12
    • 3.2.0
    • 3.2.1
    • 3.2.2
    • 3.2.3
    • 3.2.4
    • 3.2.5
    • 3.2.6
    • 3.2.7
    • 3.2.8
    • 3.2.9
    • 3.2.10
    • 3.2.11
    • 3.2.12
    • 3.3.0
    • 3.3.1
    • 3.3.2
    • 3.3.3
    • 3.3.4
    • 3.3.5
    • 3.3.6
    • 3.3.7
    • 3.3.8
    • 3.3.9
    • 3.3.10
    • 3.3.11
    • 3.3.12
    • 3.3.13
    • 3.4.0
    • 3.4.1
    • 3.4.2
    • 3.4.3
    • 3.4.4
    • 3.4.5
    • 3.4.6
    • 3.4.7
    • 3.4.8
    • 3.4.9
    • 3.4.10
    • 3.4.11
    • 3.4.12
    • 3.4.13
    • 3.5.0
    • 3.5.1
    • 3.5.2
    • 3.5.3
    • 3.5.4
    • 3.5.5
    • 3.5.6
    • 3.5.7
    • 3.5.8
    • 3.5.9
    • 3.5.10
    • 3.5.11
    • 3.5.12
    • 3.5.13
    • 3.5.14
    • 3.5.15
    • 3.5.16
    • 4.0.0
    • 4.0.1
    • 4.0.2
    • 4.0.3
    • 4.0.4
    • 4.0.5
    • 4.0.6
    • 4.0.7
    • 4.0.8
    • 4.0.9
    • 4.1.0
    • 4.1.1
    • 4.1.2

    Versions in green have been tested.

  • spring-boot-starter-web (Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container (deprecated in favor of spring-boot-starter-webmvc))
  • JDK 25

Build Tool:
Spring MVC - Serving static web content Select All Download
  • boot-serving-static-pages
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • AddCustomLocations.java
          • resources
            • META-INF
              • resources
            • my-custom-location
            • newLocation1
            • newLocation2
            • public
            • resources
            • static

    See Also

    Join