How Does Jakarta Server Pages Handle Version Support?
Jakarta Server Pages (JSP) is a component specification within the Jakarta EE platform, maintained by the Eclipse Foundation. Like all Jakarta EE component specs, it has no standalone EOL policy -- there are no official end-of-life dates published for individual JSP versions. Support ends when your application server vendor stops shipping patches for the server version that implements a given JSP spec.
JSP versions are tightly coupled to two other specs: Jakarta Servlet and the broader Jakarta EE Platform. You cannot mix and match -- the JSP version you run is determined by your app server, which in turn implements a specific Jakarta EE release. Upgrading JSP means upgrading your entire Jakarta EE stack.
The key shift to watch for is the javax.* to jakarta.* namespace change introduced in JSP 3.0 (Jakarta EE 9). Code written against JSP 2.x uses javax.servlet.jsp.*; JSP 3.0 and above uses jakarta.servlet.jsp.*. This is a source-level migration with no binary compatibility path.
References: Jakarta Pages Specification -- Eclipse Foundation | Jakarta EE Specifications
What Breaks When You Stay on an Older JSP Version?
Because JSP is compiled into Servlets at runtime, its failure modes are different from standalone frameworks. Problems rarely surface as startup errors -- they appear as subtle runtime incompatibilities, tag library failures, or broken EL expressions that only show up under specific conditions.
Tag library dependencies stop working
JSTL (Jakarta Standard Tag Library) versions are tightly coupled to JSP versions. If your app server ships a newer JSTL but your application bundles an older one to stay on JSP 2.x, you end up with classpath conflicts that are hard to diagnose. The xmlns URIs used in taglib declarations differ between the javax.* and jakarta.* namespaces, and mixing them silently breaks tag resolution.
Expression Language (EL) gaps accumulate
EL versions advance alongside JSP. Features like lambda expressions, stream operations, and collection literals in EL were added in later releases. Code written assuming EL 3.0+ behavior will either fail silently or throw evaluation errors on an older container. The worst case is an EL expression that evaluates to empty string instead of throwing -- you get wrong output with no error to investigate.
App server CVE patches stop arriving
JSP containers ship inside app servers. Once your vendor drops support for a server version -- as WildFly, Payara, and Tomcat each do on their own schedules -- you stop receiving patches for vulnerabilities in the JSP container itself, not just your application code. Tomcat, the most common JSP runtime, publishes explicit EOL dates per major version; older branches receive no security fixes regardless of the JSP spec being technically "unfrozen."
What Happens After a JSP Version Is Superseded?
The specification is frozen -- it receives no bug fixes, clarifications, or new features. The JSP compiler behavior in any conforming container is considered final for that version. In practice, this means edge cases in tag processing, EL evaluation, or .jspx handling that were never addressed in the spec simply stay broken forever.
The more immediate consequence is what happens to your runtime. Tomcat is the most widely used JSP container outside of full Jakarta EE servers. Each Tomcat major version maps to a specific Servlet and JSP spec version -- Tomcat 10.x implements JSP 3.0, Tomcat 10.1.x implements JSP 3.1, Tomcat 11.x implements JSP 4.0. Once a Tomcat major branch reaches its end of life, no further releases are issued for that branch, and any CVEs discovered after that point go unpatched. You can check the current Tomcat lifecycle at the Apache Tomcat website.
For teams running JSP inside a full Jakarta EE server (WildFly, Payara, Open Liberty, WebLogic), the vendor's own product lifecycle determines how long you receive patched builds. The JSP spec version bundled in that server version is frozen either way -- you get security patches for the server infrastructure around JSP, but the spec behavior itself does not change.
In practice, most teams on superseded JSP versions are not blocked immediately. The real cost is the widening gap between your JSP version and the ecosystem around it -- JSTL updates, EL improvements, tooling support in IDEs and build plugins, and compatibility with modern CDI and Servlet features all move on without you.
How Do You Check Which JSP Version Your Application Is Using?
The JSP version is determined by your container, not your application code. Check the container first, then verify your dependencies align.
Check your container version
For Apache Tomcat:
catalina.sh version
The output includes the Servlet and JSP spec versions the container implements. Cross-reference with the table above to identify the JSP version.
For WildFly/JBoss:
$JBOSS_HOME/bin/standalone.sh --version
Check your Maven dependencies
If you are compiling against the JSP API explicitly, check your pom.xml:
<!-- Old javax namespace (JSP 2.x) -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- New jakarta namespace (JSP 3.0+) -->
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<scope>provided</scope>
</dependency>
The artifact group ID alone tells you which namespace generation your application targets. If you see javax.servlet.jsp, you are on JSP 2.x and have not yet migrated through the namespace change.
Check at runtime via JspFactory
// Inside a JSP or Servlet
String engineInfo = JspFactory.getDefaultFactory()
.getEngineInfo()
.getSpecificationVersion();
System.out.println("JSP Spec: " + engineInfo);
FAQ
Q1: Is JSP still used in new projects?
Less commonly than a decade ago, but yes -- JSP remains in active use, particularly in large enterprise codebases and legacy applications that were built before modern templating engines became dominant. For new projects, most teams reach for Thymeleaf, Jakarta Faces (Facelets), or a separate frontend framework with a REST backend. JSP is not deprecated and remains part of the current Jakarta EE spec, but the ecosystem momentum has clearly shifted. If you are starting from scratch, you are choosing JSP for compatibility with existing code, not because it is the recommended path forward.
Q2: What is the difference between JSP 2.x and JSP 3.x?
The most significant change is the package namespace: JSP 2.x uses javax.servlet.jsp.*, while JSP 3.0 and later use jakarta.servlet.jsp.*. This is not a minor rename -- it requires source-level changes across all JSP files, tag handlers, and any Java code that references the JSP API directly. Beyond the namespace, JSP 3.1 added alignment with updated EL and Servlet versions, and JSP 4.0 tracks the changes introduced in Jakarta EE 11. The behavioral differences within a given version family are minor; the namespace migration is the real barrier.
Q3: Does JSP have an official end-of-life date?
No. Like all Jakarta EE component specifications, JSP versions do not carry official EOL dates from the Eclipse Foundation. A version is "superseded" once a newer major release ships, meaning it receives no further spec updates -- but it is never formally retired. The EOL that matters in practice is the one published by your runtime vendor. For Tomcat users, the Apache Tomcat project publishes explicit EOL dates per major branch. For full Jakarta EE server users, check your vendor's product lifecycle page. As shown in the release table above, each JSP version maps to a specific server generation.
Q4: Can I run JSP without a full Jakarta EE server?
Yes. Apache Tomcat and Eclipse Jetty both implement the Servlet and JSP specs without the full Jakarta EE platform. This is a common deployment model -- Tomcat handles JSP 2.x through the current version depending on the Tomcat major branch, and Jetty 12 supports multiple EE environments including JSP 3.0 and above. You do not need WildFly, Payara, or GlassFish to run JSP. The tradeoff is that you lose access to other Jakarta EE specs like CDI, JTA, and JPA out of the box, and you need to bring those dependencies in yourself if your application uses them.
Q5: Should I migrate from JSP to Thymeleaf or Jakarta Faces?
It depends on what you are building and why you are considering the migration. Thymeleaf works well if your team wants natural HTML templates that designers can open in a browser without a running server, or if you are already in a Spring ecosystem. Jakarta Faces (Facelets) is the better choice if you are staying within Jakarta EE and want a component model with built-in state management. Neither replaces JSP automatically -- migration requires rewriting every view. The common trigger for migration is the javax.* to jakarta.* namespace change: teams already facing that refactor often use it as an opportunity to switch templating engines at the same time, since the effort is already significant.
