Including Files (jsp:include)
Learn the difference between the runtime jsp:include action and the compile-time include directive, and build a shared header and footer.
Introduction
Almost every multi-page site shares common pieces — a header with navigation, a footer with a copyright line. Duplicating that markup in every JSP file is a maintenance nightmare. JSP gives you two different mechanisms for pulling in another file's content, and they behave very differently under the hood: the include directive and the jsp:include action.
- How the compile-time include directive works.
- How the runtime jsp:include action works.
- When to choose one over the other.
- How to build a shared header and footer for a real page.
The include Directive
The include directive, <%@ include file="..." %>, is resolved at translation time — before the page is even compiled into a servlet. The included file's text is copied and pasted directly into the including page's source, then the combined result is compiled as one servlet.
<%@ include file="header.jsp" %><h1>Dashboard</h1><p>Welcome to your dashboard.</p><%@ include file="footer.jsp" %>Because the directive merges source code before compilation, the included file shares the same request-time variables and scriptlet context as the parent page — it behaves as if you had typed its contents directly into your file.
The jsp:include Action
jsp:include is a standard action, resolved at request time (runtime), not compile time. Each request, the container calls the included page as its own separate servlet, captures its output, and merges that output into the response.
<jsp:include page="header.jsp" /><h1>Dashboard</h1><p>Welcome to your dashboard.</p><jsp:include page="footer.jsp" />Directive vs Action
| Aspect | include Directive | jsp:include Action |
|---|---|---|
| Resolved at | Translation/compile time | Request/runtime |
| Included content | Merged as raw source before compiling | Called and output captured each request |
| Performance | Slightly faster (no repeated calls) | Slightly slower (a call every request) |
| Flexibility | Static — the file path cannot be dynamic | Dynamic — page path can be an EL expression |
| Best for | Content that never changes, like a fixed footer | Content that varies, or reused compiled fragments |
Building a Shared Header and Footer
A typical layout keeps header.jsp and footer.jsp in a shared folder and includes them from every page in the app.
<!-- /common/header.jsp --><header> <h1>PrograMinds Store</h1> <nav> <a href="/home.jsp">Home</a> <a href="/products.jsp">Products</a> <a href="/cart.jsp">Cart</a> </nav></header><!-- /common/footer.jsp --><footer> <p>© 2026 PrograMinds. All rights reserved.</p></footer><!-- products.jsp --><jsp:include page="/common/header.jsp" /><main> <h2>Our Products</h2> <p>Browse our full catalog below.</p></main><jsp:include page="/common/footer.jsp" />Passing Parameters
jsp:include can pass extra parameters to the included page using nested jsp:param tags, useful for telling a shared header which nav link should be highlighted.
<jsp:include page="/common/header.jsp"> <jsp:param name="activePage" value="products" /></jsp:include><!-- inside header.jsp, reading the param --><a href="/products.jsp" class="${param.activePage == 'products' ? 'active' : ''}">Products</a>Common Mistakes
- Using the include directive with a dynamic, per-request file path — it cannot vary, since it is resolved before the page ever runs.
- Expecting jsp:param values inside an include directive — jsp:param only works with the jsp:include action.
- Forgetting that heavy use of jsp:include adds a small runtime cost on every request compared to the directive.
- Mixing incompatible HTML structure between includes, like opening a <div> in the header and never closing it, which breaks every page that includes it.
Best Practices
- Use the include directive for genuinely static, unchanging fragments like a copyright footer.
- Use jsp:include when the fragment needs parameters or independent request-time logic.
- Keep shared fragments in a dedicated folder like /common/ or /WEB-INF/includes/.
- Test that included fragments render correctly in isolation as well as inside a parent page.
Frequently Asked Questions
Yes, the page attribute can point to any resource the container can dispatch to, including a servlet mapped by URL.
No, jsp:param is only recognized inside the jsp:include action, not the compile-time directive.
jsp:include is generally the safer default for real applications since it supports parameters and dynamic paths.
Key Takeaways
- The include directive merges source code at compile time, before the servlet exists.
- jsp:include calls another page at request time and merges its output.
- jsp:include supports dynamic paths and jsp:param; the directive does not.
- Shared headers and footers keep multi-page JSP sites consistent and maintainable.
Summary
Includes solve reuse within a single response. The next lesson tackles a related but different problem: handing off an entire request to another resource entirely, using jsp:forward.