skip to content

What is Maven resource filtering, and how do you turn it on so ${} placeholders in your resource files get replaced at build time?

level: middleimportance: must knowfreq 60%

answer

  1. process-resources phase
  2. maven-resources-plugin copies + substitutes
  3. <filtering>true</filtering> opt-in
  4. off by default (binaries)
  5. Spring ${} collision -> @...@ delimiter

basics

~10 s

Resource filtering is when the maven-resources-plugin copies files from src/main/resources to target and replaces ${...} tokens inside them with property values. You enable it by setting <filtering>true</filtering> on a <resource>.

solid answer

~30 s

Filtering means the maven-resources-plugin, during the process-resources phase, copies resource files into target/classes and substitutes ${...} placeholders inside the file contents with resolved property values (project.*, env.*, user-defined, and entries from external <filters> files). It is off by default to avoid corrupting binaries; you opt in per resource directory with <resource><directory>...<filtering>true</filtering></resource> in <build>. A classic use is stamping a build.version=${project.version} into an application.properties. You must be careful with frameworks that also use ${} (like Spring), because Maven will try to resolve those tokens too — escape or change the delimiter. Filtering only affects file content, not file names.

code

xml · 8 lines
xml
<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

go deeper

for a junior

Knows ${} in a resource gets replaced when filtering is enabled.

for a middle

Knows the <filtering>true</filtering> switch, the process-resources phase, and that it is off by default.

for a senior

Handles the Spring/${} delimiter collision and separates filtered vs binary resource directories.

for a principal

Defines conventions/profiles so env-specific filtering is reproducible and binaries are never corrupted across the org.

## The problem filtering solves You often want build-time values baked into a config file — the app version, the active environment, a build timestamp. Filtering lets Maven inject those automatically. ## What filtering does During the **process-resources** phase, the **maven-resources-plugin** (`resources:resources` goal) copies everything under your resource directories into `target/classes`. When **filtering is enabled**, it also scans the *content* of each copied text file and replaces any `${...}` token with the resolved property value. It does **not** rename files or filter binaries differently — it just substitutes inside content. ## Why it is off by default Filtering text-scans files. Running it over binaries (images, keystores, fonts) can corrupt them. So Maven defaults `<filtering>` to `false` and makes you opt in. ## Enabling it ```xml <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build> ``` Now a file like `src/main/resources/application.properties`: ```properties app.name=${project.artifactId} app.version=${project.version} build.user=${env.USER} ``` becomes, in `target/classes/application.properties`, fully resolved values. ## Where values come from Filtering resolves the same property sources as the pom: user-defined `<properties>`, built-in `project.*` / `settings.*` / `env.*`, system properties, and any external `.properties` files listed under `<build><filters>`. ## The Spring/`${}` collision Frameworks like Spring also use `${}` for their own placeholders. If filtering is on for `src/main/resources`, Maven will eat Spring's tokens at build time. Fixes: keep framework placeholders in a non-filtered directory, escape them, or change the Maven filtering delimiter (the resources-plugin supports `<delimiters>` / `useDefaultDelimiters`, e.g. switch to `@...@`). ## Phase reminder Filtering runs at `process-resources`, before `compile`. So filtered files are already in `target/classes` by the time tests run.

  • Why is filtering disabled by default?
    Because it text-scans and rewrites file content; running it over binary resources (images, keystores) would corrupt them.
  • In which phase does filtering happen?
    process-resources, via the maven-resources-plugin's resources goal — before compile, so filtered files are in target/classes for tests.
  • How do you avoid Maven clobbering Spring's own ${} placeholders?
    Don't filter that file, escape the token, or change Maven's filtering delimiter to something like @prop@ via the resources plugin's <delimiters>.

saying these in an interview costs you the question

  • Claiming filtering is on by default.
  • Thinking filtering renames files or runs at compile/package time.
  • Filtering a whole resource dir that contains binaries, corrupting them.

context