# Faces Migrate

> Migrate a Jakarta Faces project from one version to another (e.g. JSF 2.3 to Faces 4.1)

- Skill: `omnifaces/faces-migrate` (Agent Skill)
- Install (CLI): `npx skillmds@latest add omnifaces/faces-migrate`
- Raw SKILL.md: https://api.skillmd.com/api/skills/omnifaces/faces-migrate/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: omnifaces (https://skillmd.com/u/omnifaces)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/omnifaces/faces-migrate

---


*Version 1.6.0*

Migrate the current project to Jakarta Faces `$ARGUMENTS` (if no argument, ask the developer for the target version).

## Step 1: Detect Current Version

Determine the current Faces version from:
- `pom.xml` or `build.gradle` dependencies (look for `javax.faces`, `jakarta.faces`, `jsf-api`, `myfaces-api`).
- `faces-config.xml` version attribute.
- XML namespaces in XHTML files (`java.sun.com` = JSF 1.0+, `xmlns.jcp.org` = JSF 2.2+, `jakarta.faces` = Faces 4.0+).
- Package imports in Java files (`javax.faces` = JSF 1.x/2.x vs `jakarta.faces` = Faces 3.0+).

Also determine the **runtime type**:
- **Full EE server** (WildFly, GlassFish, TomEE, Payara, WebSphere, Liberty, etc.): Faces, CDI, BV, EJB, JPA, JAX-RS, etc. are all provided by the runtime; the project should depend on the Java EE / Jakarta EE API artifact with `<scope>provided</scope>`, not on standalone implementations.
- **Barebones servlet container** (Tomcat, Jetty, Undertow, etc.) or **framework** (Spring Boot): Tomcat only provides Servlet, JSP, EL, WebSocket, and JASIC; everything else (Faces, CDI, BV, JSTL, etc.) must be installed/bundled separately with the application.

When updating dependencies in migration steps, update the appropriate artifact:
- On a full EE server: update the EE API version and ensure the target server version supports the target Faces version.
  - Java EE 8 (JSF 2.3): `javax:javaee-web-api:8.0` with `<scope>provided</scope>`
  - Jakarta EE 9 (Faces 3.0): `jakarta.platform:jakarta.jakartaee-web-api:9.0.0` with `<scope>provided</scope>`
  - Jakarta EE 10 (Faces 4.0): `jakarta.platform:jakarta.jakartaee-web-api:10.0.0` with `<scope>provided</scope>`
  - Jakarta EE 11 (Faces 4.1): `jakarta.platform:jakarta.jakartaee-web-api:11.0.0` with `<scope>provided</scope>`
- On a barebones servlet container: update the standalone Faces implementation version directly (e.g. `org.glassfish:jakarta.faces` for Mojarra, `org.apache.myfaces.core:myfaces-impl` for MyFaces); do NOT use `javaee-api` or `jakarta.jakartaee-api` as a substitute because it will allow compiling against APIs that the servlet container doesn't actually provide.

Report the detected version and runtime type, and confirm with the developer before proceeding.

## Step 2: Determine Migration Path

Based on source → target version, apply the relevant steps below.
Multiple steps may apply for multi-version jumps (e.g. JSF 2.0 → Faces 4.1 requires all intermediate steps).

## Migration Steps

### JSF 1.x → JSF 2.0+ (major rewrite)

This is a significant migration; confirm scope with developer before proceeding.

- Replace JSP files with Facelets (XHTML).
- Replace `<f:view>`, `<f:subview>` with Facelets templating (`<ui:composition>`, `<ui:define>`).
- Replace `<managed-bean>` entries in `faces-config.xml` with `@ManagedBean` + scope annotations (will be migrated to `@Named` in later step).
- Replace `<navigation-rule>` entries in `faces-config.xml` with return values from action methods or `?faces-redirect=true`.
- Replace `javax.faces.webapp.FacesServlet` URL pattern `/faces/*` or `*.faces` or `*.jsf` with `*.xhtml`.

### JSF 2.x → JSF 2.3 (incremental)

- Update `pom.xml` to JSF 2.3 dependency.
- Replace `@ManagedBean` + `@javax.faces.bean.*Scoped` with `@Named` + `@javax.enterprise.context.*Scoped`.
- `@ViewScoped`: replace `javax.faces.bean.ViewScoped` with `javax.faces.view.ViewScoped`.
- Replace `@javax.faces.bean.ManagedProperty` on managed beans with `@Inject`.
- Replace `@javax.faces.bean.ManagedProperty` on unmanaged variables with `@javax.faces.annotation.ManagedProperty`.
- FacesServlet: ensure URL pattern is `*.xhtml`; remove legacy `*.jsf`, `*.faces`, `/faces/*` mappings.
- Update `faces-config.xml` version to `2.3`.
  ```xml
  <faces-config 
      xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
      version="2.3"
  >
  ```
- Update `*.taglib.xml` version to `2.3`.
  ```xml
  <facelet-taglib 
      xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_3.xsd"
      version="2.3"
  >
  ```
- Update XML namespaces from `java.sun.com` to `xmlns.jcp.org` (if on JSF 2.2+).
- Use HTML5 doctype `<!DOCTYPE html>` (if on JSF 2.2+).
- If the project has a `web.xml` and its declared version lags behind Servlet 4.0 (Java EE 8), update it. If it still carries a legacy DTD-based `DOCTYPE` declaration (pre-Servlet 2.4), drop it entirely — the XML Schema `xmlns`/`xsi:schemaLocation` form below replaces it.
  ```xml
  <web-app
      xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
      version="4.0"
  >
  ```
- Ensure `beans.xml` exists in `WEB-INF/`, and update it to CDI 2.0 (Java EE 8) when it lags behind. Once a `version` attribute is present, `bean-discovery-mode` is required alongside it. Prefer `annotated`: `@Named` plus a CDI scope is a bean defining annotation, so Faces beans are discovered either way.
  ```xml
  <beans
      xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
      version="2.0"
      bean-discovery-mode="annotated"
  >
  ```
- Review for new 2.3 features to adopt: https://arjan-tijms.omnifaces.org/p/jsf-23.html

### JSF 2.3 → Faces 3.0 (Jakarta EE 9, namespace rename)

This is purely a package rename; no behavioral changes.

- Update `pom.xml` to Jakarta Faces 3.0 dependency.
- Rename ALL `javax.faces.*` imports to `jakarta.faces.*` in Java files.
- Rename ALL `javax.servlet.*` to `jakarta.servlet.*`.
- Rename ALL `javax.inject.*` to `jakarta.inject.*`.
- Rename ALL `javax.enterprise.*` to `jakarta.enterprise.*`.
- Rename ALL `javax.annotation.*` to `jakarta.annotation.*`.
- Rename ALL `javax.validation.*` to `jakarta.validation.*`.
- Rename ALL `javax.persistence.*` to `jakarta.persistence.*` (if JPA is used).
- Rename ALL `javax.ejb.*` to `jakarta.ejb.*` (if EJB is used).
- Rename ALL `javax.ws.rs.*` to `jakarta.ws.rs.*` (if JAX-RS is used).
- Update `web.xml` context param names from `javax.faces.*` to `jakarta.faces.*`.
- Move any `javax/faces/Messages*.properties` from the project's own resources to `jakarta/faces/`, keeping the locale suffixes (`Messages_it.properties`, `Messages_nl_BE.properties`, etc.).
- Rename the keys inside that bundle from `javax.faces.*` to `jakarta.faces.*` (e.g. `javax.faces.component.UIInput.REQUIRED` → `jakarta.faces.component.UIInput.REQUIRED`).
- Rename the same keys in the bundle declared by `<message-bundle>` in `faces-config.xml` and in all its locale variants, if any. The declared name is a base name; the file names are project-chosen and stay as-is, only the keys change.
- Rename `javax.validation.constraints.*.message` keys to `jakarta.validation.constraints.*.message` in `ValidationMessages*.properties`, if present.
- NOTE: bundles declared by `<resource-bundle>` in `faces-config.xml` hold application-defined keys and need no key rename.
- FacesServlet: ensure URL pattern is `*.xhtml`; remove legacy `*.jsf`, `*.faces`, `/faces/*` mappings.
- Update `faces-config.xml` namespace and version to `3.0`.
  ```xml
  <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_3_0.xsd"
      version="3.0"
  >
  ```
- Update `*.taglib.xml` namespace and version to `3.0`.
  ```xml
  <facelet-taglib 
      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-facelettaglibrary_3_0.xsd"
      version="3.0"
  >
  ```
- NOTE: XHTML namespaces stay the same (`xmlns.jcp.org`) in Faces 3.0; they only change in 4.0.
- Use HTML5 doctype `<!DOCTYPE html>` (if not already).
- If the project has a `web.xml` and its declared version lags behind Servlet 5.0 (Jakarta EE 9), update it.
  ```xml
  <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_5_0.xsd"
      version="5.0"
  >
  ```
- Update `beans.xml` namespace and version to CDI 3.0 (Jakarta EE 9), keeping the existing `bean-discovery-mode`, which stays required next to `version`.
  ```xml
  <beans
      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/beans_3_0.xsd"
      version="3.0"
      bean-discovery-mode="annotated"
  >
  ```

### Faces 3.0 → Faces 4.0+ (Jakarta EE 10+, spec overhaul)

- Update `pom.xml` to Jakarta Faces 4.0 dependency.
- Update XHTML namespaces from `xmlns.jcp.org` to `jakarta.faces` URNs:
  - `http://xmlns.jcp.org/jsf/html` → `jakarta.faces.html`
  - `http://xmlns.jcp.org/jsf/core` → `jakarta.faces.core`
  - `http://xmlns.jcp.org/jsf/facelets` → `jakarta.faces.facelets`
  - `http://xmlns.jcp.org/jsf/composite` → `jakarta.faces.composite`
  - `http://xmlns.jcp.org/jsf/passthrough` → `jakarta.faces.passthrough`
  - `http://xmlns.jcp.org/jsf` → `jakarta.faces`
  - `http://xmlns.jcp.org/jsp/jstl/core` → `jakarta.tags.core`
- Remove `xmlns="http://www.w3.org/1999/xhtml"` from XHTML files; since Faces 4.0 it is always implied.
- Remove any remaining `@ManagedBean` usage (removed in Faces 4.0); replace with `@Named` + CDI scope.
- Remove any `javax.faces.bean.*` imports (package removed entirely).
- FacesServlet: ensure URL pattern is `*.xhtml`; remove legacy `*.jsf`, `*.faces`, `/faces/*` mappings.
- Update `faces-config.xml` version to `4.0`.
  ```xml
  <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_0.xsd"
      version="4.0"
  >
  ```
- Update `*.taglib.xml` version to `4.0`.
  ```xml
  <facelet-taglib 
      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-facelettaglibrary_4_0.xsd"
      version="4.0"
  >
  ```
- Use HTML5 doctype `<!DOCTYPE html>` (if not already).
- If the project has a `web.xml` and its declared version lags behind Servlet 6.0 (Jakarta EE 10), update it.
  ```xml
  <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_0.xsd"
      version="6.0"
  >
  ```
- Make `bean-discovery-mode` explicit in `beans.xml` BEFORE bumping it to CDI 4.0. Up to CDI 3.0 an empty or version-less `beans.xml` meant `all`; since CDI 4.0 the attribute is optional and defaults to `annotated`. Every bean without a bean defining annotation then stops being discovered at runtime, and nothing fails at build time. Report the choice: keep `all` to preserve current behavior, or move to `annotated` and annotate the beans that need it.
- Update `beans.xml` version to CDI 4.0 (Jakarta EE 10), keeping the `bean-discovery-mode` decided above.
  ```xml
  <beans
      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/beans_4_0.xsd"
      version="4.0"
      bean-discovery-mode="annotated"
  >
  ```
- Review for new 4.0 features to adopt: https://balusc.omnifaces.org/2021/11/whats-new-in-faces-40.html

### Faces 4.0 → Faces 4.1 (Jakarta EE 11, incremental)

- Update `pom.xml` to Jakarta Faces 4.1 dependency.
- Update `faces-config.xml` version to `4.1`.
  ```xml
  <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"
  >
  ```
- Update `*.taglib.xml` version to `4.1`.
  ```xml
  <facelet-taglib 
      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-facelettaglibrary_4_1.xsd"
      version="4.1"
  >
  ```
- If the project has a `web.xml` and its declared version lags behind Servlet 6.1 (Jakarta EE 11), update it.
  ```xml
  <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"
  >
  ```
- Update `beans.xml` version to CDI 4.1 (Jakarta EE 11), keeping the existing `bean-discovery-mode`.
  ```xml
  <beans
      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/beans_4_1.xsd"
      version="4.1"
      bean-discovery-mode="annotated"
  >
  ```
- When the project overrides the standard message bundle (`jakarta/faces/Messages*.properties`) or declares a `<message-bundle>`, report the keys that Faces 4.1 adds so the developer can supply translations. Faces 4.1 adds two, for the new `UUIDConverter`:
  - `jakarta.faces.converter.UUIDConverter.UUID`
  - `jakarta.faces.converter.UUIDConverter.UUID_detail`
- Full state saving is deprecated for removal since 4.1 and is removed in Faces 5.0, along with both its context params in `web.xml`. Migrating them off now is what makes the next jump a version bump rather than a rewrite:
  - `jakarta.faces.PARTIAL_STATE_SAVING`: remove it when set to `true`, which is the default since 2.0. When set to `false`, report it rather than removing it; the application is running on full state saving and removing the param flips it onto partial state saving, which surfaces any custom component that does not save its state correctly; fix those first.
  - `jakarta.faces.FULL_STATE_SAVING_VIEW_IDS`: report the listed view IDs, which need the same treatment per view.
- Replace the `ActionSource2` types, all deprecated for removal since 4.1; their members moved to the `ActionSource` counterpart:
  - `jakarta.faces.component.ActionSource2` → `jakarta.faces.component.ActionSource`
  - `jakarta.faces.view.ActionSource2AttachedObjectHandler` → `jakarta.faces.view.ActionSourceAttachedObjectHandler`
  - `jakarta.faces.view.ActionSource2AttachedObjectTarget` → `jakarta.faces.view.ActionSourceAttachedObjectTarget`
- Review for new 4.1 features to adopt: https://balusc.omnifaces.org/2024/06/whats-new-in-faces-41.html

## Step 3: Execute

For each applicable migration step:
1. Show the developer what will change (file count, type of changes).
2. Confirm before proceeding.
3. Apply changes file by file.
4. After all changes, report a summary.

## Step 4: Verify

After migration:
- Check for any remaining old-version references (grep for old package names, old namespaces, old annotations).
- Check for any remaining `javax.` keys in `*.properties` files and for a leftover `javax/faces/` resource directory; these fail silently rather than at build time.
- Check that `faces-config.xml`, `web.xml` and `beans.xml` each declare a version no higher than the Faces, Servlet resp. CDI API the runtime supplies, and no lower than needed for the descriptor features in use.
- Verify `pom.xml`/`build.gradle` has no conflicting dependency versions.
- Suggest running `/faces-review` to catch any remaining issues.

## Important

- ALWAYS confirm with the developer before making changes.
- For large projects, offer to do a dry run first (report only, no changes).
- When migrating across multiple versions (e.g. JSF 2.0 → Faces 4.1), apply steps in order; do NOT skip intermediate steps.
- Preserve existing code style (indentation, line endings, import ordering).
- Third-party libraries (PrimeFaces, OmniFaces, etc.) may also need version upgrades; flag these but let the developer decide.

