On this page
1Concept
A profile is a named, versioned collection of specifications that a runtime can be certified against. Jakarta EE defines three, and they are strictly nested: every Core Profile API is in the Web Profile, and every Web Profile API is in the full Platform.
The important word is standardised. A vendor could always ship a cut-down server; what a profile adds is that the subset itself is specified and TCK-tested, so “Web Profile certified” means the same thing from every vendor.

2Why profiles exist
By Java EE 5 the full platform had grown to include a great deal that most applications never used — CORBA interoperability, JAX-RPC web services, the deployment and management APIs, remote enterprise beans. A vendor had to implement all of it to be compliant, and an application had to be deployed onto a server carrying all of it.
- For application teams — a smaller server means faster startup, a smaller memory footprint, a smaller attack surface and less to patch.
- For vendors — a lower barrier to producing a certified runtime, which increases the number of implementations and therefore the value of the standard.
- For the platform's relevance — by 2020 the competition was Spring Boot and microservice runtimes measured in tens of megabytes. A platform whose minimum unit was a 200 MB application server was losing the argument before it began.
The Web Profile arrived in Java EE 6 (2009) and was immediately successful; it is what most people actually deploy. The Core Profile arrived in Jakarta EE 10 (2022), aimed squarely at microservices and ahead-of-time compilation.
3What is in each profile
3.1 Core Profile
The smallest standard surface: enough to build a REST service and nothing more. Notably it contains no Servlet, no JPA and no JTA — a Core Profile runtime need not know what an HTTP session or a container-managed transaction is.
| Specification | Version in Jakarta EE 11 | Role |
|---|---|---|
| Jakarta RESTful Web Services | 4.0 | HTTP endpoints, the request/response programming model |
| Jakarta CDI Lite | 4.1 | Injection and lifecycle, restricted to what can be resolved at build time |
| Jakarta Dependency Injection | 2.0 | The @Inject annotation set |
| Jakarta Interceptors | 2.2 | Cross-cutting behaviour around bean methods |
| Jakarta JSON Processing | 2.1 | Low-level JSON parsing and generation |
| Jakarta JSON Binding | 3.0 | Object ↔ JSON mapping |
| Jakarta Annotations | 3.0 | Common annotations such as @Resource and @PostConstruct |
WHY CDI LITE MATTERS HERE CDI Lite is the subset of CDI that can be resolved without loading and reflecting over classes at runtime. That is what makes ahead-of-time compilation and GraalVM native images practical — and it is the whole reason the Core Profile exists as a separate tier rather than just “Web Profile minus a few things”.
3.2 Web Profile
Everything in the Core Profile, plus the full web and persistence stack. This is the profile that fits the overwhelming majority of real applications.
- Web tier — Jakarta Servlet 6.1, Faces 4.1, Pages 4.0, Expression Language 6.0, WebSocket 2.2
- Persistence and transactions — Jakarta Persistence 3.2, Jakarta Data 1.0, Jakarta Transactions 2.0
- Component model — full CDI 4.1 (not just Lite), Jakarta Enterprise Beans Lite 4.0, Jakarta Concurrency 3.1
- Cross-cutting — Jakarta Security 4.0, Authentication 3.1, Bean Validation 3.1
Note Enterprise Beans Lite: the local, transactional subset of the enterprise bean model — @Stateless, @Stateful, @Singleton, interceptors, container-managed transactions and security. What it excludes is remote invocation, message-driven beans, the timer service's persistent variants and the legacy 2.x APIs.
3.3 Full Platform
Everything in the Web Profile, plus the integration-oriented specifications.
| Added specification | Why you would need it |
|---|---|
| Jakarta Messaging 3.1 | Asynchronous messaging — queues and topics, JMS |
| Jakarta Enterprise Beans 4.0 (full) | Remote invocation and message-driven beans |
| Jakarta Batch 2.1 | Long-running chunk-oriented batch jobs with checkpointing |
| Jakarta Connectors 2.1 | JCA adapters for legacy and external enterprise systems |
| Jakarta Mail 2.1 | Sending and receiving email |
| Jakarta Authorization 3.0 | Pluggable authorization providers |
| Jakarta Activation 2.1 | MIME data typing, used by Mail |
| Application Client Container | Running managed components in a standalone client JVM |
WHAT LEFT THE PLATFORM IN JAKARTA EE 11 Jakarta XML Web Services, Jakarta XML Binding and Jakarta SOAP with Attachments were removed from the Platform, and the CORBA interoperability requirement was dropped. If you have a SOAP estate, that is now an explicit third-party dependency rather than something the server owes you.

4Selecting a profile

The decision is usually made by working downward from the full Platform and asking what you would lose, rather than upward from Core and asking what you would gain. Two questions settle it in practice:
- Do I need messaging, batch, JCA, remote beans or mail? If yes, full Platform. These are the genuinely Platform-only capabilities, and shimming them in yourself is rarely worth it.
- Do I need Servlet, JPA or container-managed transactions? If yes, Web Profile. This covers almost everything that is not a pure JSON service.
If neither applies — a stateless service that speaks JSON over HTTP, uses CDI for wiring, and talks to its datastore through a client library rather than JPA — the Core Profile is the right target, and it buys you fast startup and native-image compatibility.
4.1 Declaring the choice in a build
<!-- Core Profile -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-core-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Web Profile -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Full Platform -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>11.0.0</version>
<scope>provided</scope>
</dependency>A USEFUL DISCIPLINE Even when you deploy to a full Platform server, compile against the narrowest profile API you intend to use. The build then fails the moment someone reaches for @MessageDriven in a service that was supposed to stay Web Profile — which is far cheaper than discovering it during a runtime migration.
4.2 Profiles are a floor, not a ceiling
Most runtimes are modular and let you enable a single extra specification on top of a profile — Open Liberty's feature list and WildFly's server profiles both work this way. Adding Jakarta Messaging to an otherwise Web Profile server is entirely normal.
What you lose is the clean claim. You can no longer say “this deploys on any Web Profile server”; you have to say “Web Profile plus Messaging 3.1”. That is still a portable statement — it is just a longer one.
5Footprint and startup
The practical payoff of a narrower profile is felt in three places, and it compounds in containerised deployments where you may be starting hundreds of instances.
| Dimension | Effect of a narrower profile |
|---|---|
| Startup time | Fewer subsystems to initialise, fewer archives to scan for annotations. The difference between a Core Profile runtime and a full application server is typically an order of magnitude. |
| Memory footprint | Fewer loaded classes and fewer resident subsystems — directly relevant when you are paying per container. |
| Image size | A smaller runtime produces a smaller container image, which means faster pulls and faster scaling. |
| Attack surface | Every specification you do not ship is code that cannot have a CVE. A server with no JMS subsystem cannot have a JMS vulnerability. |
| Native compilation | Core Profile's CDI Lite is designed for build-time resolution, which is what makes GraalVM native images feasible. Full CDI's runtime reflection is not. |
DO NOT OVER-CLAIM THE SAVINGS Modern servers are modular and lazy — a full Platform server that never starts its JMS subsystem costs little more than a Web Profile one at runtime. The reliable wins from a narrow profile are image size, patch surface and native-image feasibility, not raw throughput.
6Common mistakes
- Choosing the full Platform by default. It is the safe-looking option, and it quietly permits any developer to reach for remote beans or JMS without an architectural conversation.
- Choosing Core Profile because “microservices”. If the service uses JPA and transactions — and most do — Core is the wrong target and you will spend the project fighting it.
- Confusing Enterprise Beans Lite with “EJB is in the Web Profile”. Lite has no remote interfaces and no message-driven beans. Code that compiles against full EJB will not deploy to a Web Profile server.
- Assuming Web Profile includes JMS. It does not, and it never has. This is the single most common profile surprise.
- Compiling against the full Platform API but deploying to a Web Profile server. The build passes; deployment fails, or worse, it deploys and fails at first invocation.
- Treating the profile as the only portability question. Your datasource configuration, class-loading settings and clustering setup are vendor-specific regardless of profile.
7Version considerations
| Platform version | Profiles available | Note |
|---|---|---|
| Java EE 5 and earlier | Full platform only | One size, all of it |
| Java EE 6 (2009) | Web Profile, Full | Web Profile introduced — the first admission that not everyone needs everything |
| Java EE 7 / 8 | Web Profile, Full | Web Profile contents grow with the platform |
| Jakarta EE 9 / 9.1 | Web Profile, Full | Namespace rename applies to both |
| Jakarta EE 10 (2022) | Core, Web, Full | Core Profile introduced; CDI split into Lite and Full |
| Jakarta EE 11 (2025) | Core, Web, Full | Core Profile released first (Dec 2024), then Web (Mar 2025), then Platform |
The staggered release order in Jakarta EE 11 is itself informative: the profiles are now released as independent milestones rather than as one bundle, which lets the smallest profile ship first and vendors certify incrementally.
8How to verify this yourself
- Open the Core Profile, Web Profile and Platform specification documents on
jakarta.ee/specifications. Each has a table listing exactly which specifications and versions it requires — that table is the authoritative answer to any “is X in the Web Profile?” argument. - Compile a project against
jakarta.jakartaee-web-apiand add an@MessageDrivenbean. The compilation failure is the profile boundary made visible. - Start the same trivial REST application on a Core Profile runtime and on a full application server. Compare startup time, resident memory and container image size.
- Check your chosen runtime's certification page and note which profiles it is certified for at which version — several products are certified for some profiles and not others.
9Interview questions and answers
What is a Jakarta EE profile and why does the platform have them?
A profile is a standardised, TCK-tested subset of the platform's specifications. There are three — Core, Web and full Platform — and they are strictly nested.
They exist because the full platform accumulated a great deal that most applications never use. Profiles let an application target a smaller runtime while keeping a portability guarantee, and they lower the barrier for vendors to produce certified implementations. The alternative — every vendor shipping its own ad-hoc subset — would destroy the portability the standard exists to provide.
What is in the Core Profile, and what is deliberately not?
It contains Jakarta RESTful Web Services, CDI Lite, Dependency Injection, Interceptors, JSON Processing, JSON Binding and Annotations — roughly seven specifications.
What is deliberately absent is as telling: no Servlet, no Persistence, no Transactions, no Faces. A Core Profile runtime need not know what an HTTP session or a container-managed transaction is. It is scoped to “stateless JSON service” and nothing beyond that.
Why does the Core Profile use CDI Lite rather than full CDI?
Because CDI Lite is the subset that can be resolved at build time, without runtime classpath scanning and reflection. That is the enabling condition for ahead-of-time compilation and GraalVM native images.
Full CDI relies on runtime discovery — scanning archives, reflecting over classes, building the bean graph as the container starts — which a native image cannot do. Splitting CDI into Lite and Full in Jakarta EE 10 is what made the Core Profile possible at all; it is not a convenience trim, it is the architectural point.
Is JMS part of the Web Profile?
No. Jakarta Messaging is a full Platform specification and has never been in the Web Profile. This is the most common profile surprise in practice — teams assume a Web Profile server can inject a JMSContext and discover otherwise at deployment.
In practice most Web Profile runtimes let you enable a messaging feature on top, which is fine; you just have to state the dependency as “Web Profile plus Messaging” rather than claiming plain Web Profile.
What is Enterprise Beans Lite, and how does it differ from the full specification?
Lite is the local, in-process subset included in the Web Profile: @Stateless, @Stateful, @Singleton, interceptors, container-managed transactions, declarative security and the non-persistent timer service.
Full Enterprise Beans adds remote invocation, message-driven beans, persistent timers and the legacy 2.x APIs. Practically: if your bean has a @Remote interface or is driven by a queue, you need the full Platform. If it is a local transactional service, Lite is enough — which is what the overwhelming majority of applications actually use.
How would you choose a profile for a new system?
I would start from the full Platform and subtract, because the questions are sharper that way.
- Does it need messaging, batch, JCA or remote beans? If yes → full Platform.
- Does it need Servlet, JPA or container-managed transactions? If yes → Web Profile.
- Is it a stateless JSON service with CDI wiring and no relational mapping? → Core Profile.
Then I would compile against the API artifact for the chosen profile even if we deploy to a larger server, so the build enforces the boundary. Discovering a profile violation at compile time costs minutes; discovering it during a runtime migration costs weeks.
If I deploy to a full Platform server anyway, does the profile choice still matter?
Yes, for two reasons. First, it constrains what the team can use — compiling against the Web Profile API makes an accidental dependency on messaging a build failure rather than an architectural drift nobody noticed. Second, it keeps future options open: if you later want to move to a lighter runtime or a native image, the work is already done.
The profile is as much a governance tool as a deployment decision. It is how you write down “this service is not allowed to grow into an integration hub” in a form the compiler can check.
What are the real benefits of a narrower profile, and what benefits are overstated?
Real: smaller container images, a smaller patch and CVE surface, faster cold start, and — for the Core Profile specifically — native-image feasibility.
Overstated: steady-state throughput and memory. Modern servers are modular and lazily initialised, so a full Platform server that never starts its JMS subsystem costs very little more than a Web Profile one once it is warm. I would not justify a profile choice on request latency; I would justify it on image size, security surface and startup, which is where the difference is actually measurable.
Can you add a single specification on top of a profile, and what does that cost you?
Yes — most runtimes are feature-based and this is routine. What it costs is the simplicity of the portability claim. Instead of “runs on any Web Profile server” you now have “runs on any Web Profile server that also provides Jakarta Messaging 3.1”.
That is still a standards-based, portable statement, and it is a far better position than reaching for a vendor-proprietary messaging API. I would just make sure it is written down in the architecture decision record, because it is exactly the kind of detail that gets lost and then surprises someone during a runtime migration three years later.
When did each profile appear, and what does that history tell you?
The Web Profile arrived in Java EE 6 in 2009; the Core Profile in Jakarta EE 10 in 2022.
The thirteen-year gap is the interesting part. The Web Profile was a response to the platform being too big for typical web applications. The Core Profile was a response to something different — the rise of microservices, containers and native compilation, where the competition was runtimes measured in tens of megabytes with sub-second startup. The platform's answer was not to shrink the whole thing but to standardise a genuinely small tier and make CDI resolvable at build time to support it.