skip to content

Static Resource Handling

Resource handlers map URL paths to classpath or filesystem locations, with resolver chains for caching and content-hash versioning. Comes up whenever an app serves a built frontend from the same jar.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

How do you serve static files (CSS, JS, images) in Spring MVC, and where does Spring Boot look for them by default?

level: juniorimportance: must knowfreq 70%

answer

  1. static/public/resources/META-INF classpath dirs
  2. addResourceHandler = URL, addResourceLocations = disk
  3. backed by ResourceHttpRequestHandler
  4. controllers win over static (low order)
  5. spring.web.resources.add-mappings=false

basics

~10 s

Put files under src/main/resources/static (or public/resources/META-INF/resources) and Spring Boot serves them automatically at the URL root. To configure manually, override addResourceHandlers in a WebMvcConfigurer.

solid answer

~30 s

Spring Boot auto-serves static content from classpath:/static/, classpath:/public/, classpath:/resources/, and classpath:/META-INF/resources/ — a file at static/css/app.css is reachable at /css/app.css. Under the hood these are registered as resource handlers backed by ResourceHttpRequestHandler. To customize, implement WebMvcConfigurer and override addResourceHandlers(ResourceHandlerRegistry), calling addResourceHandler("/assets/**").addResourceLocations("classpath:/static/"). The URL pattern is what clients request; the location is where files physically live (classpath or filesystem). Spring Boot's default mapping is /** with a configurable base path (spring.web.resources.static-locations). You can turn it off with spring.web.resources.add-mappings=false. This is separate from controller mapping — static handlers have the lowest precedence so controllers win on path conflicts.

code

java · 9 lines
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**")
                .addResourceLocations("classpath:/static/", "file:/opt/uploads/")
                .setCachePeriod(3600); // seconds
    }
}

go deeper

for a junior

Should know the default folders and that Boot serves them automatically.

for a middle

Should know addResourceHandlers/addResourceLocations and classpath vs file locations.

for a senior

Should explain the ResourceHttpRequestHandler backing and precedence vs controllers.

for a principal

Should discuss disabling defaults, base-path patterns, and serving user uploads from filesystem vs CDN tradeoffs.

## What 'static resources' means Static resources are files served as-is without any controller logic: CSS, JavaScript, images, fonts, HTML. Unlike a `@Controller` method that builds a response dynamically, static content is read from a location (classpath or filesystem) and streamed to the client. ## Spring Boot defaults Out of the box, Spring Boot serves static content from four classpath locations (highest to lowest precedence): - `classpath:/META-INF/resources/` - `classpath:/resources/` - `classpath:/static/` - `classpath:/public/` A file at `src/main/resources/static/css/app.css` is served at URL `/css/app.css` (the folder name `static` is NOT part of the URL). The default URL pattern is `/**`, configurable via `spring.web.resources.static-locations` and the base path via `spring.mvc.static-path-pattern` (e.g. `/resources/**`). ## The mechanism: addResourceHandlers + ResourceHttpRequestHandler Internally, Spring MVC maps static content by registering **resource handlers**. You do this by implementing `WebMvcConfigurer` and overriding `addResourceHandlers(ResourceHandlerRegistry registry)`: - `addResourceHandler("/assets/**")` — the **URL pattern** clients request. - `.addResourceLocations("classpath:/static/", "file:/opt/uploads/")` — one or more **physical locations** to look in, checked in order. Each registration produces a `ResourceHttpRequestHandler` — the actual handler that resolves a request path to a `Resource`, checks Last-Modified/ETag, sets caching headers, and writes bytes. The `SimpleUrlHandlerMapping` created from the registry has a low order, so `@RequestMapping` controllers take precedence when paths overlap. ## Location string prefixes - `classpath:/static/` — resources bundled in the jar/classpath. - `file:/opt/uploads/` — filesystem directory (useful for user-uploaded content served without a CDN). - A trailing slash is required on directory locations. ## Turning it off / customizing - `spring.web.resources.add-mappings=false` disables the default static handlers entirely. - Adding your own `addResourceHandlers` registration supplements (does not replace) the defaults unless you disable them. ## Gotchas - Path traversal (`../`) is blocked by Spring's `PathResourceResolver`, which verifies the resolved resource is inside the configured location. - Static handlers do not run through your controller filters unless configured; but globally registered `HandlerInterceptor`s do apply. - In Spring Boot 2.x properties were `spring.resources.*`; in Boot 2.4+/3.x they are `spring.web.resources.*`.

  • If a controller maps /assets/report and a static file also exists at that path, which wins?
    The controller. Resource handlers are registered via SimpleUrlHandlerMapping with a low (late) order, so annotated handler mappings are consulted first and take precedence.
  • What's the difference between addResourceHandler and addResourceLocations?
    addResourceHandler defines the URL pattern clients request (e.g. /assets/**); addResourceLocations defines one or more physical places (classpath:/... or file:/...) searched in order to find the file.

saying these in an interview costs you the question

  • Thinking the folder name (static/public) appears in the URL
  • Believing you must write a controller to serve every image or CSS file
  • Claiming filesystem locations aren't supported — file: prefix works
  • Confusing addResourceLocations with addResourceHandler

context

open as a page

How do you control HTTP caching for static resources in Spring MVC (cache-period, Cache-Control, ETags)?

level: middleimportance: should knowfreq 55%

basics

~10 s

Use setCachePeriod(seconds) or setCacheControl(CacheControl.maxAge(...)) on the resource handler registration to emit Cache-Control/Expires headers. Spring also auto-adds Last-Modified and ETag support for conditional requests.

open as a page

Compare classpath: and file: resource locations for static content. When would you serve from the filesystem, and what are the security concerns?

level: seniorimportance: should knowfreq 35%

basics

~20 s

classpath: locations are bundled in the jar (immutable, deploy-time). file: locations point to a directory on disk (mutable at runtime), useful for user uploads. Both go through PathResourceResolver, which blocks path traversal outside the configured root.

open as a page

What is the ResourceResolver / ResourceChain, and what are the built-in resolvers in Spring MVC?

level: seniorimportance: should knowfreq 40%

basics

~10 s

A ResourceChain is an ordered pipeline of ResourceResolver objects that turn a request path into an actual Resource. Built-ins include PathResourceResolver, CachingResourceResolver, VersionResourceResolver, EncodedResourceResolver, and WebJarsResourceResolver.

open as a page

Design a static-asset cache-busting strategy in Spring MVC using content versioning. Contrast ContentVersionStrategy with FixedVersionStrategy and address URL generation.

level: principalimportance: nice to knowfreq 25%

basics

~10 s

Enable a VersionResourceResolver with addContentVersionStrategy (per-file MD5 hash in the filename) so each file's URL changes only when its content changes. Serve with long, immutable Cache-Control, and generate versioned URLs via ResourceUrlProvider in templates.

open as a page