JSTL (Jakarta Standard Tag Library)
A standard library of XML-like tags for JavaServer Pages that provides declarative iteration, conditionals, formatting, XML processing, and SQL access, replacing raw Java scriptlets in JSP views.
Created by Sun Microsystems / Java Community Process (JSR 52 expert group, led by Pierre Delisle)
JSTL — originally the JSP Standard Tag Library, and since the move to the Eclipse Foundation known as the Jakarta Standard Tag Library — is a standard collection of XML-style tags for use inside JavaServer Pages. Rather than mixing raw Java into pages with scriptlets, a developer writes declarative markup such as <c:forEach>, <c:if>, and <fmt:formatDate> to handle the everyday page-logic tasks of iteration, conditionals, URL handling, internationalized formatting, XML processing, and (in its original form) basic database access. JSTL is not a standalone programming language; it is a tag-based templating vocabulary layered on top of JSP and the JSP Expression Language, with the explicit goal of letting page authors express common dynamic-page patterns without ever writing Java.
First standardized by Sun Microsystems in 2002 under JSR 52 of the Java Community Process, JSTL crystallized practices that had emerged in countless ad-hoc JSP custom tag libraries during the late 1990s. Its arrival, together with the JSP 2.0 Expression Language, marked the moment when the Java community decisively turned away from scriptlets and toward a cleaner separation between business logic and HTML templates.
History & Origins
By the early 2000s, JSP had a serious problem: pages were routinely littered with Java scriptlets — <% ... %> blocks containing loops, conditionals, database calls, and formatting code. JSP 1.1 (1999) had introduced custom tag libraries, but every project and framework reinvented the same tags for “iterate over a collection,” “render conditionally,” “format a date,” and so on. The result was fragmentation and a steep learning curve for newcomers.
The Java Community Process responded with JSR 52, the “Standard Tag Library for JavaServer Pages,” with Pierre Delisle of Sun Microsystems serving as specification lead. The expert group included representatives from major Java vendors and open-source projects. The resulting JSTL 1.0 specification was finalized in June 2002, and a reference implementation was published through the Apache Taglibs project (originally hosted by the Jakarta project at Apache, in a confusing-but-coincidental naming overlap with the much later Jakarta EE).
JSTL 1.0 was structured as four tag libraries, identified by their URIs and conventional namespace prefixes:
- Core (
c) — iteration, conditionals, variable manipulation, URL handling, output escaping. - Formatting / I18N (
fmt) — locale-sensitive number, date, and time formatting plus resource-bundle-based message lookup. - XML (
x) — parsing and processing of XML documents, with XPath-based expressions. - SQL (
sql) — direct database access from pages (intended for prototyping and small applications, not production architecture).
JSTL 1.0 also defined its own miniature expression language so that tag attributes like items="${customers}" could reference page data — a sibling effort to what would soon become the JSP Expression Language.
JSTL 1.1, released alongside JSP 2.0 in late 2003, retired JSTL’s private expression language in favor of the new, JSP-wide Expression Language (EL), eliminating duplication. JSTL 1.2 (around 2006, part of Java EE 5) aligned with the unified EL shared between JSP 2.1 and JavaServer Faces 1.2. After that, the specification entered a long period of stability under JSR 52 maintenance, with the bulk of activity moving to the reference implementation rather than the standard itself.
When Oracle contributed Java EE to the Eclipse Foundation in 2017 and the platform was rebranded Jakarta EE, JSTL followed: the package namespace and tag-library URIs migrated from javax.servlet.jsp.jstl.* to jakarta.servlet.jsp.jstl.* in Jakarta Standard Tag Library 2.0 (with Jakarta EE 9, around late 2020). Jakarta Standard Tag Library 3.0 (with Jakarta EE 10, around 2022) modernized dependencies and tracked newer Servlet, JSP, and EL versions.
Design Philosophy
JSTL embodies several deliberate design choices:
- Declarative over imperative. Page logic is expressed as XML-style tags whose attributes are evaluated by the container, not as Java statements. A page author can read and write JSTL without knowing Java syntax.
- Standardize the common cases. JSTL deliberately covers the 80% of page-logic needs — looping, branching, formatting, escaping — rather than trying to be a general-purpose language.
- Lean on the Expression Language. Tag attributes accept EL expressions such as
${order.total}, so JSTL composes naturally with whatever data the controller exposes through request, session, or application scopes. - Encourage MVC separation. JSTL was deliberately positioned as a view-layer technology. Even the SQL library was documented from the start as appropriate only for prototyping; real applications were expected to keep database code in the model.
- Tag-library, not language extension. JSTL is implemented entirely as JSP custom tag libraries, so it requires no changes to the JSP language or the servlet container — any JSP-compliant container can use it by adding the JAR.
Key Features
A JSTL page typically begins by declaring one or more taglib directives, then uses tags interspersed with HTML:
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<html>
<body>
<h1>Orders for <c:out value="${user.name}" /></h1>
<c:choose>
<c:when test="${empty orders}">
<p>No orders yet.</p>
</c:when>
<c:otherwise>
<table>
<c:forEach var="order" items="${orders}" varStatus="row">
<tr class="${row.index mod 2 == 0 ? 'even' : 'odd'}">
<td><c:out value="${order.id}" /></td>
<td><fmt:formatDate value="${order.placedAt}" type="date" /></td>
<td><fmt:formatNumber value="${order.total}" type="currency" /></td>
</tr>
</c:forEach>
</table>
</c:otherwise>
</c:choose>
</body>
</html>
Notable tag groups include:
- Core flow:
<c:if>,<c:choose>/<c:when>/<c:otherwise>,<c:forEach>,<c:forTokens>. - Variable and output:
<c:set>,<c:remove>,<c:out>(with automatic HTML escaping by default). - URL handling:
<c:url>,<c:param>,<c:redirect>,<c:import>. - Formatting and I18N:
<fmt:formatDate>,<fmt:formatNumber>,<fmt:parseDate>,<fmt:parseNumber>,<fmt:message>,<fmt:bundle>,<fmt:setLocale>. - XML:
<x:parse>,<x:out>,<x:if>,<x:forEach>with XPath expressions. - SQL (legacy / prototyping):
<sql:query>,<sql:update>,<sql:transaction>. - Functions library: a set of EL functions such as
fn:length,fn:contains,fn:toUpperCase, available via thefnprefix.
The <c:out> tag’s default behavior of HTML-escaping its value made it an important safety feature in an era when cross-site scripting was a common JSP pitfall.
Evolution
JSTL’s evolution has been quiet by design. After the burst of activity that produced JSTL 1.0, 1.1, and 1.2 between 2002 and 2006, the specification settled into long-term stability. There was no JSTL 2.0 in the old javax namespace; the next major version was the Jakarta rename, which adopted the 2.0 version number to reflect the breaking namespace change rather than new features. Jakarta Standard Tag Library 3.0 continued the modernization, tracking the broader Jakarta EE 10 platform.
The reference implementation has had a more interesting journey. The original implementation lived in the Apache Taglibs project under the name standard-taglib, often shipped simply as jstl.jar or standard.jar. After the Jakarta EE move, the reference implementation transitioned to the Eclipse Foundation, and modern Jakarta containers either bundle a compatible implementation or pull it in as a dependency.
Around JSTL, the broader Java view-layer landscape shifted dramatically. JavaServer Faces (JSF) introduced a component-based alternative, Facelets replaced JSP as JSF’s view technology, and template engines such as Thymeleaf and FreeMarker offered competing approaches. Each of these absorbed lessons from JSTL — particularly the value of standardized iteration and conditional constructs, and tight integration with an expression language.
Current Relevance
JSTL today is firmly a maintained-but-mature technology rather than a growing one. New Java web applications increasingly default to Spring Boot with Thymeleaf or with client-side single-page-application frameworks consuming JSON APIs, both of which sidestep JSP and JSTL entirely. However, JSTL is far from dead:
- It remains an actively maintained Jakarta EE specification, with Jakarta Standard Tag Library 3.0 published as part of Jakarta EE 10.
- Every major servlet container — Apache Tomcat, Jetty, WildFly/JBoss, GlassFish, Open Liberty, Oracle WebLogic — supports JSTL out of the box or via a small dependency.
- The vast installed base of Struts-and-JSP and Spring-MVC-and-JSP applications, especially in banking, insurance, telecom, and government, continues to depend on JSTL for day-to-day page logic.
For developers maintaining or modernizing such codebases, JSTL is a practical, low-ceremony skill: a handful of tag libraries that, together with the JSP Expression Language, cover most of the page-logic surface area without any Java code in the page.
Why It Matters
JSTL was a quiet but pivotal step in the maturation of Java web development. By standardizing the page-logic tags that every project had been reinventing, it broke the cycle of incompatible custom tag libraries and gave the community a shared vocabulary. Together with the JSP 2.0 Expression Language, it ended the era of scriptlet-heavy pages and made the Model-View-Controller separation the default in Java web frameworks. Its tag-and-expression model influenced later view technologies inside the Java ecosystem — JavaServer Faces, Facelets, Spring’s form and tag libraries — and outside it, in template engines that adopted similarly declarative iteration and conditional constructs. Even as newer view technologies have taken center stage, JSTL endures as one of the most widely deployed templating libraries in enterprise software, and as a small but consequential chapter in the story of how the Java web learned to keep its HTML clean.
Timeline
Notable Uses & Legacy
Apache Struts applications
Struts 1 and Struts 2 web applications, which dominated enterprise Java web development in the early-to-mid 2000s, commonly used JSTL tags such as <c:forEach> and <c:if> in their JSP views to iterate over action results and conditionally render markup.
Spring MVC web applications
A large body of Spring Framework web applications historically pair Spring's controllers and form tag library with JSTL in JSP views, using <c:forEach>, <c:url>, and <fmt:formatDate> for iteration, link generation, and locale-sensitive formatting.
Apache Tomcat and Jasper
Tomcat's Jasper JSP engine ships with full support for JSTL through bundled implementations (historically the Apache Taglibs project), making JSTL one of the most widely deployed tag libraries on the Java web.
Enterprise and government portals
Banking, insurance, telecom, and public-sector web applications built on Java EE through the 2000s and 2010s extensively relied on JSTL to keep raw Java out of JSP pages, and many of these systems remain in production and under active maintenance.
Content management and learning platforms
Java-based content management systems, learning management systems, and portal servers that render server-side HTML have used JSTL for templating tasks such as menu rendering, pagination, and internationalized message lookup via <fmt:message>.
Language Influence
Influenced By
Influenced
Running Today
Run examples using the official Docker image:
docker pull tomcat:latestExample usage:
docker run --rm -p 8080:8080 -v $(pwd):/usr/local/tomcat/webapps/ROOT tomcat:latest