Static resource access failures in Spring Boot typically stem from incorrect directory placement, conflicting security configurations, or missing MVC auto-configuration. By verifying that assets reside in the standard classpath locations like src/main/resources/static and ensuring that no custom WebSecurityConfigurerAdapter blocks anonymous access to these paths, you can restore immediate availability of CSS, JavaScript, and images without complex server adjustments.
Understanding the Default Static Resource Locations
Spring Boot is designed with a convention-over-configuration approach that automatically serves static content if it is placed in specific directories within the classpath. When you run your application, the framework scans for resources in a predefined order. If your files are not in these exact locations, the embedded Tomcat server will return a 404 Not Found error even if the file exists physically on your disk. The default search order for static resources is as follows:- /META-INF/resources/: Resources here are served but have lower priority than the root static folder.
- /resources/: This is an alternative location often used in older projects or specific build setups.
- /static/: This is the most common location. Any file placed here is accessible via the root URL path.
- /public/: Similar to the static folder, this is also checked by the auto-configuration.
logo.png inside src/main/resources/static/images/logo.png, it becomes available at the URL /images/logo.png. It is crucial to understand that the directory name itself does not appear in the URL; only the relative path from the static folder matters. Misplacing a file in src/main/java or a non-standard folder like src/main/assets will prevent Spring Boot from detecting it automatically.
Verifying Directory Structure and Build Output
A frequent cause of this issue is a mismatch between where developers store files during development and where the build tool places them during execution. If you are using Maven or Gradle, ensure that your resources are indeed inside thesrc/main/resources tree. Sometimes, IDEs may create folders outside the source root, which means they are ignored during compilation.
To verify that your resources are being packaged correctly, inspect the target output directory. For a Maven project, check the target/classes directory. You should see your static folder and its contents nested directly under classes. If the folder is missing there, your build configuration might be filtering out those files, or you might have placed them in the wrong source directory entirely.
Additionally, check for typos in your folder names. The string must be exactly static, not Statics or static_files. Spring Boot’s ResourceHandler is case-sensitive and strict about these naming conventions. If you are working with a multi-module project, ensure that the module containing the web resources is properly included in the classpath of the main boot application.
Checking Security Configuration Interference
If your static resources are in the correct location but still inaccessible, the most likely culprit is Spring Security. In many applications, security rules are configured to restrict access to certain endpoints. By default, Spring Security permits all requests to static resources, but this behavior can be overridden by custom configurations. If you have implemented a customWebSecurityConfigurerAdapter (in Spring Boot 2.x) or a SecurityFilterChain bean (in Spring Boot 3.x), you must explicitly allow access to your static paths. Without this allowance, the security filter chain intercepts the request before it reaches the resource handler, resulting in a 401 Unauthorized or 403 Forbidden response.
In legacy configurations, you would add a rule like this:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/images/**").permitAll()
.anyRequest().authenticated();
}
In modern Spring Boot 3 applications using the new functional or bean-based security model, you need to ensure that the permitAll directive covers your static directories. Failing to do so creates a silent failure where the browser cannot load stylesheets or scripts, leading to a broken user interface. Reviewing your security logs can help identify if a request is being denied by the security filter rather than the resource handler.
Disabling Caching During Development
Sometimes, resources exist and are permitted, but the browser serves a stale version, making it seem like the file is missing or outdated. Spring Boot disables caching for static resources by default when the application runs in dev mode, but this setting can be inadvertently changed in production profiles or through explicit configuration. You can control caching headers by modifying yourapplication.properties or application.yml file. Setting spring.web.resources.cache.period=0 ensures that every request checks for updates. This is particularly useful when debugging static asset issues because it prevents the browser from holding onto old versions of JavaScript bundles or CSS files that may have been updated on the server.
If you are using Thymeleaf or other template engines, ensure that your view templates correctly reference the static resources. A common mistake is hardcoding absolute paths instead of using the context-relative syntax provided by the template engine, which can break resource resolution when the application context path changes.
Frequently Asked Questions
Why do I get a 404 error for my CSS files?
This usually indicates that the CSS file is not located in one of the default static directories such as /static or /public. Verify that the file path matches the URL pattern exactly, excluding the leading slash of the base URL.
Can I change the default static resource location?
Yes, you can customize the static resource locations by adding properties to your application.properties file. Use spring.web.resources.static-locations to specify a list of paths that Spring Boot should scan for static assets.
Does Spring Security block static resources by default?
No, Spring Security allows anonymous access to static resources by default. However, if you define a custom security configuration, you must explicitly permit access to these paths using permitAll() for the relevant URL patterns.
How can I check if my resources are being loaded?
Open your browser's developer tools and look at the Network tab. Filter by XHR or Document types to see if the server returns a 200 OK status for your static files. If you see 404 or 403 errors, the issue is either with file placement or security permissions.
What is the difference between /static and /public folders?
Functionally, there is no difference; both are scanned by the same auto-configuration mechanism. The choice between them is largely stylistic, though /static is more commonly used in community examples and tutorials.