Freemarker
Template Reading
Java
Resources Folder
Tutorial

How to read Freemarker Template files from src/main/resources folder?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Freemarker templates placed under src/main/resources should be loaded from the classpath, not from a source-code path on disk. That distinction matters because src/main/resources exists during development, but after packaging the application into a JAR, those files are no longer regular source files.

If you configure Freemarker to read from the classpath, the same code will work in your IDE, during tests, and in production deployments. That is the reliable pattern to aim for.

Put Templates Under a Clear Resource Root

A common project layout looks like this:

text
src/main/resources/templates/invoice.ftl
src/main/resources/templates/email/welcome.ftl

The important part is choosing one template root, such as templates, and keeping all .ftl files under it. Freemarker will then resolve template names relative to that root.

Load Templates from the Classpath

In plain Java, the simplest configuration is setClassForTemplateLoading or setClassLoaderForTemplateLoading.

java
1import freemarker.template.Configuration;
2import freemarker.template.Template;
3import freemarker.template.TemplateExceptionHandler;
4
5public class TemplateLoaderExample {
6    public static void main(String[] args) throws Exception {
7        Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
8        cfg.setClassLoaderForTemplateLoading(
9            Thread.currentThread().getContextClassLoader(),
10            "templates"
11        );
12        cfg.setDefaultEncoding("UTF-8");
13        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
14
15        Template template = cfg.getTemplate("invoice.ftl");
16        System.out.println(template.getName());
17    }
18}

This tells Freemarker to search the classpath for templates/invoice.ftl. You do not pass src/main/resources/templates/invoice.ftl because that is a build-time directory, not the runtime resource path.

Render a Template After Loading It

Once the configuration is set up, rendering works the same way regardless of whether the application is running from an IDE or from a packaged artifact.

java
1import freemarker.template.Configuration;
2import freemarker.template.Template;
3import freemarker.template.TemplateExceptionHandler;
4
5import java.io.StringWriter;
6import java.util.HashMap;
7import java.util.Map;
8
9public class TemplateRenderExample {
10    public static void main(String[] args) throws Exception {
11        Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
12        cfg.setClassLoaderForTemplateLoading(
13            Thread.currentThread().getContextClassLoader(),
14            "templates"
15        );
16        cfg.setDefaultEncoding("UTF-8");
17        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
18
19        Template template = cfg.getTemplate("email/welcome.ftl");
20
21        Map<String, Object> model = new HashMap<>();
22        model.put("name", "Ada");
23
24        StringWriter out = new StringWriter();
25        template.process(model, out);
26        System.out.println(out);
27    }
28}

If the template contains Hello ${name}!, the output will be Hello Ada!.

Using setClassForTemplateLoading

If you prefer, you can load relative to a specific class instead of the thread context class loader:

java
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setClassForTemplateLoading(TemplateLoaderExample.class, "/templates");
Template template = cfg.getTemplate("invoice.ftl");

This is also a good option. The main rule is the same: use a classpath root, not a filesystem path that depends on the project being unpacked.

Why Filesystem Paths Break

This is the mistake many examples make:

java
cfg.setDirectoryForTemplateLoading(new File("src/main/resources/templates"));

It may work locally because the source tree is present. It usually breaks when the application is packaged and deployed, because the templates now live inside a JAR rather than an accessible folder on disk. Filesystem loading is only appropriate when you intentionally keep templates outside the application artifact.

Spring Boot Note

If you are using Spring Boot with the Freemarker starter, Boot already defaults to classpath template loading. In that case, put templates under src/main/resources/templates and let the framework wire the loader. Manual configuration is more common in plain Java or custom setups.

Common Pitfalls

  • Passing src/main/resources/... to Freemarker instead of the runtime classpath path.
  • Mixing setDirectoryForTemplateLoading with packaged JAR deployments and expecting it to keep working.
  • Choosing one template root in code but storing templates under a different resource folder.
  • Forgetting to set UTF-8, which can produce garbled output for non-ASCII text.
  • Swallowing template exceptions and making missing files or missing model keys harder to debug.

Summary

  • Templates under src/main/resources should be loaded from the classpath at runtime.
  • Use setClassLoaderForTemplateLoading or setClassForTemplateLoading with a clear root such as templates.
  • Request templates by names relative to that root, such as invoice.ftl or email/welcome.ftl.
  • Avoid filesystem paths unless the templates are intentionally external to the application.
  • With classpath loading, the same Freemarker code works in development, tests, and packaged deployments.

Course illustration
Course illustration

All Rights Reserved.