Versions & Implementations

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against Jakarta Faces 4.1 (Jakarta EE 11, API artifact jakarta.faces-api 4.1.2, Java SE 17 or later), Eclipse Mojarra 4.1.17 and Apache MyFaces Core 4.1.4, with Java 21 for the examples. The versions were checked on 2026-10-08 against Maven Central, the Jakarta EE specification pages and the project sites. Jakarta Faces 4.0 (Jakarta EE 10, Java SE 11 or later; Mojarra 4.0.26, MyFaces 4.0.4) is still widely deployed, so every section says where 4.0 behaves differently. Jakarta Faces 5.0 (Jakarta EE 12, Java SE 21 or later) is under development: the latest milestone of the API is 5.0.0-M9 (2026-09-18) and everything said about it here is described as upcoming, never as current behaviour. The examples belong to the running Bookshelf scenario of this section — a catalogue of books, authors and reviews — and were compiled in a scratch Maven project on JDK 26 with --release 21.

Specification versus implementation

Jakarta Faces is a specification: a document, an API, a tag library description and a technology compatibility kit (TCK) published by the Eclipse Foundation under the Jakarta EE Specification Process. The 4.1 specification page links the specification document, the Javadoc, the JavaScript documentation, the render kit documentation, the tag documentation (VDLDoc) and the TCK, and lists the Maven coordinates jakarta.faces:jakarta.faces-api as the API artifact. An implementation is a separate product that passes the TCK and is then listed as a compatible implementation. Two implementations are in production use:

  • Eclipse Mojarra, the former reference implementation, developed in the Eclipse EE4J project. Eclipse GlassFish is the compatible platform that the 4.1 specification page lists next to Mojarra.

  • Apache MyFaces Core, the Apache Software Foundation implementation, which also ships inside several other products and has its own site and configuration reference.

The practical consequences are these. Application code compiles against the API only, so the dependency on jakarta.faces-api has scope provided when the server brings its own implementation. A server that does not (Tomcat, a plain Servlet container, an embedded runtime) needs an implementation in the WAR. Anything implementation specific — context parameters in the com.sun.faces or org.apache.myfaces namespace, internal classes, default values that the specification leaves open — is a portability risk and is covered in the next section.

flowchart TB spec["Jakarta Faces 4.1 specification
document, API, VDLDoc, JavaScript docs"] api["jakarta.faces-api 4.1.2
compile against this"] tck["Faces TCK"] moj["Eclipse Mojarra 4.1.x
org.glassfish:jakarta.faces"] myf["Apache MyFaces Core 4.1.x
myfaces-api + myfaces-impl"] web["Jakarta EE 11 Web Profile"] plat["Jakarta EE 11 Platform"] core["Jakarta EE 11 Core Profile
no Faces"] srv["Servers: GlassFish, Payara, WildFly, Open Liberty ..."] lib["PrimeFaces 16, OmniFaces 5
run on any compatible implementation"] spec --> api spec --> tck tck -. "certifies" .-> moj tck -. "certifies" .-> myf api -. "implemented by" .-> moj api -. "implemented by" .-> myf web --> spec plat --> web srv --> plat srv --> moj lib --> api core -. "does not include" .-> spec

The Maven snippets below show the three ways to put Faces on the class path of the Bookshelf WAR. The first is for a Jakarta EE server: nothing is packaged. The other two package an implementation. The Mojarra artifact org.glassfish:jakarta.faces already contains the API classes, so with Mojarra the provided API dependency is only needed to compile against a specific API version when the server supplies the runtime; the MyFaces implementation artifact pulls its API artifact myfaces-api in transitively, and the API comes from MyFaces itself rather than from jakarta.faces-api. All three variants were built with mvn package in the scratch project.

Dependencies for a Jakarta EE 11 server, for Mojarra in the WAR and for MyFaces in the WAR
<!-- A: Jakarta EE 11 server (GlassFish 8, Payara 7, WildFly 40 or later ...): API only, provided by the server -->
<dependency>
  <groupId>jakarta.platform</groupId>
  <artifactId>jakarta.jakartaee-web-api</artifactId>
  <version>11.0.0</version>
  <scope>provided</scope>
</dependency>

<!-- B: Tomcat 11 or a Servlet container, with Eclipse Mojarra 4.1.x -->
<dependency>
  <groupId>jakarta.faces</groupId>
  <artifactId>jakarta.faces-api</artifactId>
  <version>4.1.2</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>jakarta.faces</artifactId>
  <version>4.1.17</version>
</dependency>

<!-- C: Tomcat 11 or a Servlet container, with Apache MyFaces Core 4.1.x (use A or the Servlet API for the rest) -->
<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-api</artifactId>
  <version>4.1.4</version>
</dependency>
<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-impl</artifactId>
  <version>4.1.4</version>
</dependency>

A real project uses one of the three blocks, not all of them. Variant B is the one the Tomcat and Weld page of this section builds on, and variant C appears again on the Spring Boot with JoinFaces and Quarkus pages, where MyFaces is a common choice. The jakartaee-web-api artifact (the Web Profile) is enough for a Faces application; the full jakarta.jakartaee-api is only needed if the code also uses Platform-only specifications.

Eclipse Mojarra versus Apache MyFaces

Both implementations pass the Faces TCK, so a portable application behaves the same on either. The differences are in what surrounds the specification.

Table 1. Mojarra and MyFaces compared (versions of 2026-10-08)
Aspect Eclipse Mojarra Apache MyFaces Core

Latest 4.1 and 4.0 releases

4.1.17 and 4.0.26

4.1.4 and 4.0.4

Maven coordinates

org.glassfish:jakarta.faces (API and implementation in one jar)

org.apache.myfaces.core:myfaces-api and myfaces-impl (two jars)

Java baseline per the project docs

4.0 needs Java 11, 3.0 and 2.3 need Java 8

4.1 needs Java 17, 4.0 needs Java 11, 3.0 and 2.3 need Java 8

Servlet, EL, CDI required (4.1)

as required by Faces 4.1

Servlet 6.1 or later, EL 6.0, CDI 4.1; JSTL 3.0 and Bean Validation 3.1 are optional

Support policy

The site states that Eclipse does not support Faces 2.2 and lower

The 2.0, 2.1 and 2.2 lines are documented as old versions

Own configuration namespace

com.sun.faces.*

org.apache.myfaces.*

Documentation of its parameters

The source of the configuration class

A reference table on the 4.1 page of the site, with "since" and default columns

Development lines

4.1.x and 4.0.x are both patched; master is Faces 5.0

4.1.x and 4.0.x; a 5.0 line is announced as "in development, not yet released"

MyFaces 4.0 is a new code base. The MyFaces 4.0 page says that it is based on the 2.3-next branch and is a completely new code base compared with 3.0 and 2.3: shared modules and dependencies were removed, the size is about 1 MB smaller, it has no dependencies, it is said to be up to 15% faster when the lambda meta factory is enabled, the JavaScript was rewritten in TypeScript and the default parameters were tuned for usability and performance.

Release cadence. Counting the versions published on Maven Central, Mojarra published seventeen 4.1 releases (4.1.1 on 2024-06-25 up to 4.1.17 on 2026-09-18) and patched the 4.0 line to 4.0.26 in the same period, which is roughly one release every seven weeks. MyFaces published five 4.1 releases (4.1.0 on 2024-12-04 up to 4.1.4 in September 2026), a slower rhythm. Both lines receive fixes after a new minor version appears, so staying on the latest patch of the line you use is the normal upgrade path. Faces 4.1 itself was ratified on 2024-06-04, six months before MyFaces 4.1.0; the specification page lists Mojarra 4.1.1 and the two GlassFish 8 milestones as the implementations that certified it.

Context parameters. Parameters whose names start with jakarta.faces. are defined by the specification and are read by both implementations; examples are jakarta.faces.PROJECT_STAGE, jakarta.faces.FACELETS_REFRESH_PERIOD, jakarta.faces.STATE_SAVING_METHOD and jakarta.faces.ENABLE_WEBSOCKET_ENDPOINT. Names that start with com.sun.faces. belong to Mojarra and names that start with org.apache.myfaces. belong to MyFaces. The defaults differ, which matters when an application moves from one to the other.

Table 2. Implementation specific parameters with the same purpose and different names and defaults
Purpose Mojarra (default) MyFaces (default)

Views remembered per session with server state saving

com.sun.faces.numberOfViewsInSession (15)

org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION (20)

Compress the serialized state

com.sun.faces.compressViewState (true)

org.apache.myfaces.COMPRESS_STATE_IN_CLIENT (false) and org.apache.myfaces.COMPRESS_STATE_IN_SESSION (true)

Encrypt the client-side view state

not compared here; see the configuration class linked below

org.apache.myfaces.USE_ENCRYPTION (true), org.apache.myfaces.SECRET, org.apache.myfaces.ALGORITHM (AES)

Early flush of the head element

no equivalent compared here

org.apache.myfaces.EARLY_FLUSH_ENABLED (false)

Reflection versus lambda accessors

not applicable

org.apache.myfaces.USE_LAMBDA_METAFACTORY (false)

Threaded view building

com.sun.faces.enableThreading (false)

not applicable

An implementation reads only its own parameters, so the example below configures the same intent for both. Replace the values with the numbers your own load test justifies; keeping fewer remembered views reduces the memory used by server state saving per session, at the price of the browser’s Back button failing earlier.

web.xml fragment that sets the project stage and the number of remembered views for each implementation
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd"
         version="6.1">

  <!-- defined by the specification: read by Mojarra and MyFaces -->
  <context-param>
    <param-name>jakarta.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>

  <!-- Mojarra only -->
  <context-param>
    <param-name>com.sun.faces.numberOfViewsInSession</param-name>
    <param-value>10</param-value>
  </context-param>

  <!-- MyFaces only -->
  <context-param>
    <param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name>
    <param-value>10</param-value>
  </context-param>

  <servlet>
    <servlet-name>facesServlet</servlet-name>
    <servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>facesServlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
</web-app>

Telling the two apart at run time. A page or a log line that reports the implementation helps when a bug report must name it. The bean below decides from the package of the Application object and reads the API version from the manifest of the API jar; the view prints both.

A request-scoped bean and a Facelets view that report the running implementation
package org.example.bookshelf.web;

import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Named;

@Named
@RequestScoped
public class RuntimeInfoBean {

    public String getImplementation() {
        String applicationClass = FacesContext.getCurrentInstance().getApplication().getClass().getName();
        if (applicationClass.startsWith("com.sun.faces.")) {
            return "Eclipse Mojarra";
        }
        if (applicationClass.startsWith("org.apache.myfaces.")) {
            return "Apache MyFaces";
        }
        return "Unknown (" + applicationClass + ")";
    }

    public String getApiVersion() {
        String version = FacesContext.class.getPackage().getImplementationVersion();
        return version != null ? version : "not declared";
    }
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html">
  <h:head><title>Bookshelf runtime</title></h:head>
  <h:body>
    <p>Implementation: <h:outputText value="#{runtimeInfoBean.implementation}"/></p>
    <p>API version: <h:outputText value="#{runtimeInfoBean.apiVersion}"/></p>
  </h:body>
</html>

Jakarta EE profiles and where Faces sits

Jakarta EE is published as three specifications that list what a compatible product must provide: the Platform, the Web Profile (a subset aimed at web applications) and the Core Profile (a much smaller subset for microservice runtimes). Faces belongs to the first two.

  • The Jakarta EE 11 Web Profile specification lists Jakarta Faces 4.1 among its required specifications. Its introduction describes the profile as a complete web stack with presentation and state management (Faces and Pages), Servlet, Enterprise Beans Lite, and so on.

  • The Jakarta EE 11 Platform contains the Web Profile specifications and more; its specification has a chapter on the requirements for Faces 4.1.

  • The Jakarta EE 11 Core Profile does not include Faces. Its release notes list updates of Annotations, Interceptors, CDI and RESTful Web Services only, and its specification text does not mention Faces. A Core Profile runtime such as a MicroProfile server therefore needs Faces added as a library or as a server feature.

The same relationship holds one release earlier: Jakarta EE 10 includes Jakarta Faces 4.0 in the Platform and in the Web Profile. For Jakarta EE 12 the Platform and Web Profile pages announce the update "Jakarta Faces 4.1 to 5.0" and a minimum of Java SE 21; that release is still being planned.

Table 3. Jakarta EE releases, the profiles that contain Faces and the Java baseline
Jakarta EE Faces Profiles with Faces Core Profile has Faces Minimum Java SE of the release

8

2.3

Platform, Web Profile

not applicable

Java 8 (the requirement of Mojarra and MyFaces 2.3)

9 and 9.1

3.0

Platform, Web Profile

not applicable

Java 8 (Mojarra and MyFaces 3.0); the 9.1 compatibility list shows builds certified on Java 8 and on Java 11

10

4.0

Platform, Web Profile

no

Java SE 11

11

4.1

Platform, Web Profile

no

Java SE 17

12 (planned)

5.0

Platform, Web Profile

not decided here

Java SE 21

What this means for a project. If the target is "any Jakarta EE 11 Web Profile server", declare jakarta.jakartaee-web-api as provided and write only standard Faces. If the target is Tomcat or a Core Profile runtime, package an implementation as in variants B or C above, and remember that CDI, Expression Language and Bean Validation have to be present as well; the Tomcat and Weld page of this section does that. The Jakarta EE servers page covers the servers one by one.

The Java baseline of each version

Each Faces release raised the minimum Java version together with its Jakarta EE release. The 4.0 and later values are printed on the specification pages as "Minimum Java SE Version"; for the older versions the table uses the requirements published by the implementations, because the specification pages of 2.x do not state one.

Table 4. Minimum Java SE per Faces version
Faces Java SE Source of the number

2.0 and 2.1

5

MyFaces 2.0 and 2.1 requirements (Java 1.5)

2.2

6

MyFaces 2.2 requirements (Java 1.6)

2.3

8

MyFaces 2.3 and the Mojarra site

3.0

8

MyFaces 3.0 and the Mojarra site

4.0

11

Faces 4.0 specification page and the change log (aligned with Jakarta EE 10)

4.1

17

Faces 4.1 specification page and its change log (aligned with Jakarta EE 11)

5.0 (upcoming)

21

Faces 5.0 specification page (Java SE 21 or higher)

Two details are easy to get wrong. First, running on a newer JDK than the minimum is normal — the examples of this section use Java 21 and compile with JDK 26 — but the minimum decides which language features the API may use: Faces 4.1 requires Java 17, so records are fine in beans and jakarta.faces.view.ViewScoped beans may be written as classes that use List.of. Second, the application server may demand more than Faces: MyFaces 4.1 lists Servlet 6.1, EL 6.0 and CDI 4.1 as requirements, which is why it needs a Servlet container of the Tomcat 11 generation.

The version matrix

The matrix joins the specification line to the libraries and servers around it. The Faces, Jakarta EE and Java columns come from the specification pages. The implementation columns give the last line of each project as published on Maven Central. The server column lists the products that the Jakarta EE site shows as certified for that release.

Table 5. Faces, Jakarta EE, Java, implementations and libraries
Faces Jakarta EE Java SE Mojarra and MyFaces OmniFaces (Faces / Java) Certified servers (jakarta.ee)

2.3

8

8

Mojarra 2.3.21, MyFaces 2.3.12

3.x (2.3 / Java 8), latest 3.14.26

Eclipse GlassFish 5.1

3.0

9 and 9.1

8 (9.1 also 11)

Mojarra 3.0.5, MyFaces 3.0.4

4.x (3.0 and 4.0 / Java 11), latest 4.7.15

GlassFish 6.0 and 6.1, WildFly Preview 23, Open Liberty beta

4.0

10

11

Mojarra 4.0.26, MyFaces 4.0.4

4.x (3.0 and 4.0 / Java 11), latest 4.7.15

GlassFish 7, WildFly 33, Open Liberty, Payara 6

4.1

11

17

Mojarra 4.1.17, MyFaces 4.1.4

5.x (4.1 and 5.0 / Java 17), latest 5.5.5

GlassFish 8, Payara 7, Open Liberty 26.0.0.5 (Platform and Web Profile); WildFly 40 added Jakarta EE 11 support

5.0 (upcoming)

12 (planned)

21

Mojarra 5.0.0 milestones; MyFaces 5.0 not released

OmniFaces 5.x lists 5.0 as its upper Faces version

none yet

PrimeFaces. One jar serves several Faces versions. PrimeFaces 16.0.0 (2026-09-04) is documented as requiring a Java 11 or later runtime and a Faces implementation, and its Maven download page offers the single artifact org.primefaces:primefaces for "Jakarta Faces (4.0 - 5.0, jakarta namespace)". The 15.x line (15.0.18) is the previous one. The PrimeFaces dependency page still lists older Faces versions in a table, so treat the download page as the statement for the jakarta line. PrimeFaces Extensions has a matching 16.0.0.

Servers. The Jakarta EE site lists, for the Jakarta EE 11 Platform, Eclipse GlassFish 8.0.0-M12, Azul Payara 7.0.0 and Payara Community 7.2026.5, and Open Liberty 26.0.0.5; for the Web Profile, GlassFish, Payara and Open Liberty; and for the Core Profile, WildFly 34 and Open Liberty. The WildFly project announced that its 40 release delivers Jakarta EE 11 support. Apache TomEE 10.2.0 implements Jakarta EE 10 and the TomEE 11 download is a 11.0.0-M1 milestone for Jakarta EE 11. Tomcat is a Servlet container and not a Jakarta EE product: Faces on Tomcat means packaging an implementation, CDI (Weld) and Expression Language, as in variants B and C above. At the time of writing the current GlassFish is 8.0.5, WildFly 41.0.1.Final, Payara 7.2026.9 and Open Liberty 26.0.0.10 with the faces-4.1 feature; the certification lists above name earlier builds because they are the ones submitted for certification.

What is new, deprecated and removed in each version

The appendix "Change Log" of the specification lists every issue per release, back to 2.0. The summaries below keep what matters to a Bookshelf developer. Each version has one short example, written with current names, for a feature that first appeared in that version.

Faces 2.0 (JSR 314, Java EE 6)

Faces 2.0 changed how applications are built, and it is the version that the older books describe most. It made Facelets the standard view declaration language, so XHTML views replaced JSP views. It introduced composite components, built-in Ajax with f:ajax and the JavaScript API, a resource handling mechanism for scripts, style sheets and images, system events, view parameters and bookmarkable URLs, implicit navigation, the project stage, annotations such as the component and converter registrations, and the integration with Bean Validation. Its own managed bean facility (javax.faces.bean) was part of 2.0. It is also the release behind most of the instructions of the 2.0 era books, which the section on outdated material below explains.

Ajax in a Facelets view: the 2.0 mechanism, written with the current namespace
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:f="jakarta.faces.core"
      xmlns:ui="jakarta.faces.facelets">
  <h:head><title>Catalogue</title></h:head>
  <h:body>
    <h:form id="search">
      <h:inputText id="q" value="#{catalogue.query}">
        <f:ajax event="keyup" listener="#{catalogue.search}" render="results"/>
      </h:inputText>
      <h:panelGroup id="results" layout="block">
        <ui:repeat value="#{catalogue.results}" var="title">
          <p>#{title}</p>
        </ui:repeat>
      </h:panelGroup>
    </h:form>
  </h:body>
</html>
The backing bean of the search form (view scoped, with an Ajax listener)
package org.example.bookshelf.web;

import jakarta.faces.event.AjaxBehaviorEvent;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import java.io.Serializable;
import java.util.List;

@Named("catalogue")
@ViewScoped
public class CatalogueBean implements Serializable {

    private static final List<String> TITLES = List.of("Dune", "Neuromancer", "Solaris", "Hyperion");

    private String query = "";
    private List<String> results = TITLES;

    public String getQuery() { return query; }
    public void setQuery(String query) { this.query = query; }
    public List<String> getResults() { return results; }

    public void search(AjaxBehaviorEvent event) {
        String needle = query == null ? "" : query.toLowerCase();
        results = TITLES.stream().filter(t -> t.toLowerCase().contains(needle)).toList();
    }
}

Faces 2.1

Faces 2.1 was a small release: the change log records the facelets-processing element, the facelet-cache-factory element in the configuration schema, and a change to the Restore View phase that calls ViewHandler.deriveLogicalViewId() before locating the view declaration language. Nothing in an application usually changes between 2.0 and 2.1, which is why many projects say "2.x" for both. The example is the Restore View entry point that you can observe with a phase listener; the lifecycle page of this section explains the phases.

A phase listener that logs the start of Restore View, the phase in which 2.1 added the logical view id step, and its registration
package org.example.bookshelf.web;

import jakarta.faces.event.PhaseEvent;
import jakarta.faces.event.PhaseId;
import jakarta.faces.event.PhaseListener;
import java.util.logging.Logger;

public class RestoreViewLogger implements PhaseListener {

    private static final Logger LOG = Logger.getLogger(RestoreViewLogger.class.getName());

    @Override
    public void beforePhase(PhaseEvent event) {
        LOG.fine(() -> "entering " + event.getPhaseId());
    }

    @Override
    public void afterPhase(PhaseEvent event) { }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }
}
<faces-config xmlns="https://jakarta.ee/xml/ns/jakartaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_1.xsd"
              version="4.1">
  <lifecycle>
    <phase-listener>org.example.bookshelf.web.RestoreViewLogger</phase-listener>
  </lifecycle>
</faces-config>

Faces 2.2 (JSR 344, Java EE 7)

The change log lists four big-ticket features: HTML5 friendly markup (passthrough attributes and elements), resource library contracts, Faces Flows and stateless views. Alongside them 2.2 added the UIViewAction component (the f:viewAction tag, first from the Seam Faces module), the ClientWindow abstraction for browser tabs and windows, file upload with h:inputFile, the CDI @ViewScoped annotation in jakarta.faces.view (the successor of the managed bean view scope), @FlowScoped, protected views, FlashFactory, the transient attribute on f:view for stateless views, and a new XML namespace (http://xmlns.jcp.org/jsf/...) for the tag libraries. The release deprecated StateManager in favour of StateManagementStrategy, deprecated the CURRENT_COMPONENT attributes and announced that javax.faces.bean would be deprecated in the next version.

A bookmarkable book page with a view parameter and a view action (Faces 2.2), and the flow-scoped bean of the borrow wizard
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:f="jakarta.faces.core">
  <f:metadata>
    <f:viewParam name="id" value="#{bookDetails.id}" required="true"/>
    <f:viewAction action="#{bookDetails.load}"/>
  </f:metadata>
  <h:head><title>Book</title></h:head>
  <h:body>
    <h1>#{bookDetails.title}</h1>
  </h:body>
</html>
package org.example.bookshelf.web;

import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import java.io.Serializable;

@Named("bookDetails")
@ViewScoped
public class BookDetailsBean implements Serializable {

    private Long id;
    private String title;

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getTitle() { return title; }

    /** Runs after the view parameters were applied and validated. */
    public void load() {
        title = "Book #" + id;
    }
}
package org.example.bookshelf.web;

import jakarta.faces.flow.FlowScoped;
import jakarta.inject.Named;
import java.io.Serializable;

/** State of the borrow wizard; lives while the flow with id "borrow" is active. */
@Named
@FlowScoped("borrow")
public class BorrowFlowBean implements Serializable {

    private String reader;

    public String getReader() { return reader; }
    public void setReader(String reader) { this.reader = reader; }
}

Faces 2.3 (JSR 372, Java EE 8)

Faces 2.3 is the version in which Faces became a full CDI citizen. The change log lists WebSocket integration (f:websocket and the CDI @Push annotation), multi-field validation with f:validateWholeBean, java.time support in f:convertDateTime, the use of CDI to evaluate the Faces specific implicit objects in expressions, @Inject on Faces artefacts (converters, validators and others become injectable), the CDI replacement for @ManagedProperty (ManagedProperty in the annotation package, used together with @Inject), UIData and ui:repeat over Map and Iterable, registerable DataModel implementations (FacesDataModel), h:commandScript, an enhanced component search facility (the search expressions used by f:ajax execute and render), f:importConstants, and the @FacesConfig annotation that activates the CDI-based features. It also deprecated javax.faces.bean, the managed bean facility of 2.0. Backward compatibility is preserved unless a CDI bean carries @FacesConfig or one of three named context parameters is set.

Pushing a "new review" message to every open browser (Faces 2.3 WebSocket support)
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" version="6.1">
  <context-param>
    <param-name>jakarta.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name>
    <param-value>true</param-value>
  </context-param>
</web-app>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:f="jakarta.faces.core">
  <h:head><title>Live reviews</title></h:head>
  <h:body>
    <f:websocket channel="reviews" onmessage="function(message) { console.log(message); }"/>
  </h:body>
</html>
package org.example.bookshelf.web;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.push.Push;
import jakarta.faces.push.PushContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;

@Named
@ApplicationScoped
public class ReviewFeedBean {

    @Inject
    @Push(channel = "reviews")
    private PushContext reviews;

    public void announce(String summary) {
        reviews.send(summary);
    }
}

Faces 3.0 (Jakarta EE 9)

Faces 3.0 added no features. Its change log has one entry: the namespace changed from javax.faces to jakarta.faces. That is a binary-breaking change for every import, every faces-config.xml and every library: PrimeFaces, OmniFaces and any custom component have to be rebuilt against the new package names. The XML namespaces of the tag libraries (http://xmlns.jcp.org/jsf/...) did not change in 3.0; they changed in 4.0. Jakarta EE 9.1 ran the same API on Java 11.

The same bean annotations before and after the Jakarta namespace change
package org.example.bookshelf.web;

// Faces 2.3 and earlier (Java EE 8) imported javax.faces.view.ViewScoped and javax.inject.Named.
// Faces 3.0 and later (Jakarta EE 9 or later) import the jakarta packages:
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;

@Named
@ViewScoped
public class ReviewFormBean implements java.io.Serializable {
    private String text;
    public String getText() { return text; }
    public void setText(String text) { this.text = text; }
}

Faces 4.0 (Jakarta EE 10)

Faces 4.0 combined new features with a clean-up that removed everything that had been deprecated or superseded. The specification page and change log list the following.

  • New: an API to create Facelets programmatically; automatic extensionless mapping of the FacesServlet; @ClientWindowScoped; custom cookie attributes such as SameSite in ExternalContext#addResponseCookie(); multiple and accept on h:inputFile; FacesContext#getLifecycle(); f:selectItemGroups and f:selectItemGroup; the type attribute of h:inputText; UIViewRoot#getDoctype(); onerror on f:websocket; layout="list" for h:selectManyCheckbox and h:selectOneRadio; annotation literals for all qualifiers; a more convenient UIComponent#subscribeToEvent(); omission of the type attribute of link and script when the doctype is HTML5; and better f:ajax behaviour in composite components.

  • Renamed: "JSF" became "Faces" everywhere, and the tag library namespaces changed from the http://xmlns.jcp.org/jsf/... URLs to the jakarta.faces.* URNs (jakarta.faces.html, jakarta.faces.core, jakarta.faces.facelets, jakarta.faces.composite, jakarta.faces.passthrough), with jakarta.tags.core for the Jakarta Standard Tag Library.

  • Removed: all JSP support, the native managed beans (@ManagedBean and related), MethodBinding, ValueBinding and their relatives, the CURRENT_COMPONENT constants of UIComponent, the deprecated methods of StateManager, and the whole ResourceResolver class. The version element of @FacesConfig has no effect any more and is deprecated for removal; the annotation itself still activates Faces and its CDI features. The JavaScript library file is the resource faces.js of the library jakarta.faces, which replaced jsf.js.

  • Baseline: Java SE 11, aligned with Jakarta EE 10.

A tab-local draft of a review with @ClientWindowScoped, and the 4.0 namespaces in a view
package org.example.bookshelf.web;

import jakarta.faces.lifecycle.ClientWindowScoped;
import jakarta.inject.Named;
import java.io.Serializable;

@Named
@ClientWindowScoped
public class WizardWindowBean implements Serializable {

    private String draft = "";

    public String getDraft() { return draft; }
    public void setDraft(String draft) { this.draft = draft; }
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="jakarta.faces.html"
      xmlns:f="jakarta.faces.core"
      xmlns:ui="jakarta.faces.facelets"
      xmlns:cc="jakarta.faces.composite"
      xmlns:pt="jakarta.faces.passthrough"
      xmlns:c="jakarta.tags.core">
  <h:head><title>Draft review</title></h:head>
  <h:body>
    <h:form>
      <h:inputTextarea value="#{wizardWindowBean.draft}" pt:placeholder="Write your review"/>
      <h:commandButton value="Save draft"/>
    </h:form>
  </h:body>
</html>

Faces 4.1 (Jakarta EE 11)

Faces 4.1 is a small release aligned with Jakarta EE 11. The specification page states that it removes references to the SecurityManager, aligns further with CDI and provides various small enhancements and clarifications.

  • New: @Inject Flow currentFlow to inject the current flow; UUIDConverter; the rowStatePreserved property of UIRepeat, the same as in UIData; events for @Initialized, @BeforeDestroyed and @Destroyed of the built-in scopes; generic FacesMessage#VALUES and VALUES_MAP; ExternalContext.setResponseContentLengthLong; equals(), hashCode() and toString() on FacesMessage; the if attribute of f:viewAction in the VDL; and a default of jakarta.faces.FACELETS_REFRESH_PERIOD when the project stage is Development.

  • Deprecated: full state saving, PreDestroyCustomScopeEvent and PostConstructCustomScopeEvent, and composite:extension.

  • Removed: references to the SecurityManager.

  • Baseline: Java SE 17.

Reading the current flow in the borrow wizard (Faces 4.1)
package org.example.bookshelf.web;

import jakarta.faces.flow.Flow;
import jakarta.faces.flow.FlowScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.io.Serializable;

@Named
@FlowScoped("borrow")
public class BorrowFlowInfoBean implements Serializable {

    @Inject
    private Flow currentFlow;

    public String getFlowId() {
        return currentFlow.getId();
    }
}

Faces 5.0 (upcoming, Jakarta EE 12)

Faces 5.0 is not released. The specification page is marked as under development, sets the minimum at Java SE 21 and lists the planned work grouped by theme. Anything below can still change, and Mojarra 5.0 and MyFaces 5.0 are milestones or snapshots. Read the list as the direction of travel, and do not rely on it for a production design.

  • Planned features: Content Security Policy support (issue 590), oninput-style HTML5 events for UIInput, and a new SUCCESS severity for FacesMessage. Content Security Policy is not absent from the 4.x implementations meanwhile: Mojarra has had its own opt-in nonce support since 4.0.16, configured with the implementation parameters com.sun.faces.enableCspNonce (a nonce per request, stamped on the scripts Mojarra renders) and com.sun.faces.cspPolicy (the policy header, default script-src 'self' 'nonce-#{nonce}' 'strict-dynamic'), and PrimeFaces offers its own CSP support. The 5.0 work standardises the idea under jakarta.faces names, which Mojarra 4.1.17 does not read; the security page shows both.

  • API modernisation: generics across converters, validators, SelectItem, ValueChangeEvent, StateHelper and others; enums for PhaseId and for FacesMessage.Severity; enums for context parameters that accept a fixed set of values.

  • Removals and clean-up: removal of everything marked @Deprecated(forRemoval = true, since = "4.0") (which includes the version element of @FacesConfig), removal of composite:extension and of the custom scope events, removal of the old XML namespaces, a possible deprecation of prependId on h:form, and splitting the API from the implementation code (step one).

  • CDI, EL and Facelets: observing phase events with @Observes, observable non-component Faces events, f:importConstants allowed everywhere rather than only in f:metadata, and Expression Language 6.0 Optional and Record resolvers in the resolver chain.

  • Behaviour and specification fixes: a clearModel attribute for f:resetValues, passthrough on facets, a placeholder attribute for h:inputText and h:inputTextarea, an HttpOnly Flash cookie (issue 1201 on the 5.0 milestone, so a 5.0 item, not a 4.x change), and the documentation of jakarta.faces.AUTOMATIC_EXTENSIONLESS_MAPPING.

For the platform, the Jakarta EE 12 pages announce Faces 4.1 to 5.0, Servlet 6.1 to 6.2 and, for Expression Language, the step from 6.0 to 6.1. To try a milestone in a scratch project without touching the production line, add it to a separate branch of the build and keep the 4.1 dependencies in the main one.

Trying the latest 5.0 milestone of the API in a scratch project (not for production)
<dependency>
  <groupId>jakarta.faces</groupId>
  <artifactId>jakarta.faces-api</artifactId>
  <version>5.0.0-M9</version>
  <scope>provided</scope>
</dependency>

The changes at a glance

Table 6. Added, deprecated and removed, by version
Version Added Deprecated Removed

2.0

Facelets as the VDL, composite components, f:ajax, resources, system events, view parameters, project stage, Bean Validation, javax.faces.bean managed beans

nothing

2.1

small clarifications, facelet-cache-factory, facelets-processing

nothing

2.2

Faces Flows, @ViewScoped (CDI), HTML5 passthrough, resource library contracts, stateless views, h:inputFile, f:viewAction, protected views, ClientWindow

StateManager, the CURRENT_COMPONENT attributes

nothing

2.3

f:websocket and @Push, CDI injection of Faces artefacts, ManagedProperty (CDI), f:validateWholeBean, java.time, search expressions, f:importConstants, h:commandScript

javax.faces.bean

nothing

3.0

nothing

nothing

javax.faces namespace replaced by jakarta.faces

4.0

programmatic Facelets, extensionless mapping, @ClientWindowScoped, SameSite cookies, f:selectItemGroups, faces.js

@FacesConfig version element

JSP, native managed beans, MethodBinding and ValueBinding, ResourceResolver, deprecated StateManager methods, old tag library URLs replaced by URNs

4.1

UUIDConverter, rowStatePreserved on UIRepeat, injectable Flow

full state saving, composite:extension, the custom scope events

SecurityManager references

5.0 (upcoming)

CSP support, generics and enums, SUCCESS severity, placeholder

candidate: prependId on h:form

planned: items deprecated for removal since 4.0, old XML namespaces

Choosing a version in practice

  • New project, Jakarta EE 11 server or Tomcat 11: Faces 4.1 with Mojarra 4.1.x or MyFaces 4.1.x, Java 21, PrimeFaces 16 and OmniFaces 5.

  • Existing Jakarta EE 10 estate: Faces 4.0 with Mojarra 4.0.26 or MyFaces 4.0.4 and Java 11 or 17; OmniFaces 4.x is the matching line. Moving to 4.1 is mostly a Java 17 and server upgrade.

  • Still on javax.faces (Faces 2.x, Java EE 8): the move to jakarta.faces is the big step; the migrating to Jakarta Faces page collects it. Go to 4.0 or 4.1 directly instead of stopping at 3.0.

  • Faces 5.0: read the milestone notes (the migration page lists what is planned); do not plan production on it before the specification ballot completes.

See also Java, Web UI frameworks for Spring Boot and Starting a new project when the version decision is part of a wider technology choice, and Vaadin and Thymeleaf for the alternatives covered on this site.

Where the books are outdated

All eight books consulted for this section date from 2004 to 2015 and describe JSF 1.0 to 2.2 (and PrimeFaces 4 and 5). On versions and implementations they are outdated in these ways, and the official documentation wins in every case.

  • They name javax.faces everywhere; since 3.0 the package is jakarta.faces, and the tag library namespaces moved from the java.sun.com and xmlns.jcp.org URLs to the jakarta.faces.* URNs in 4.0.

  • They show JSP views, JSP tag handlers and TLDs (and standalone Facelets 1.x with a custom ViewHandler); Facelets has been built in since 2.0 and all JSP support was removed in 4.0.

  • They use @ManagedBean and the javax.faces.bean scopes; the facility was deprecated in 2.3 and removed in 4.0, replaced by CDI @Named and the jakarta.enterprise.context scopes plus jakarta.faces.view.ViewScoped.

  • They know Sun’s reference implementation and Apache MyFaces 1.x/2.0; today the lines are Mojarra 4.1.x and MyFaces 4.1.x, MyFaces 4.0 is a rewritten code base, and Eclipse documents no support for Faces 2.2 and earlier.

  • They mention jsf.js, MethodBinding, ValueBinding, ResourceResolver and deprecated StateManager methods; jsf.js became faces.js and the others were removed in 4.0.

  • They are silent on Faces Flows, CDI @ViewScoped, passthrough markup, resource library contracts, stateless views, h:inputFile, f:viewAction, f:websocket, CDI injection, java.time, search expressions, @ClientWindowScoped, UUIDConverter, Jakarta Security, JoinFaces and Quarkus, which the rest of the section introduces, and on the Jakarta EE profiles.

  • They describe libraries that ended (RichFaces, Tomahawk, Trinidad, Seam 2, Apache Shale) and portlet bridges; current choices are PrimeFaces, OmniFaces and Jakarta Security (security), covered on their own pages.