diff --git a/documentation/jetty/antora.yml b/documentation/jetty/antora.yml
index ed38ab88e76c..360e7c29ed74 100644
--- a/documentation/jetty/antora.yml
+++ b/documentation/jetty/antora.yml
@@ -15,6 +15,7 @@ asciidoc:
ee-prev: ee10
ee-prev-caps: EE 10
run-jetty-classpath: ${settings.localRepository}/org/eclipse/jetty/tests/jetty-testers/${project.version}/jetty-testers-${project.version}.jar${path.separator}${run.jetty.classpath}
+ servlet-current-version: 6.1.0
nav:
- modules/operations-guide/nav.adoc
- modules/programming-guide/nav.adoc
diff --git a/documentation/jetty/modules/code/examples/pom.xml b/documentation/jetty/modules/code/examples/pom.xml
index f40e0c86397c..ac864e2f1bbf 100644
--- a/documentation/jetty/modules/code/examples/pom.xml
+++ b/documentation/jetty/modules/code/examples/pom.xml
@@ -34,6 +34,10 @@
org.eclipse.jetty
jetty-client
+
+ org.eclipse.jetty
+ jetty-deploy
+
org.eclipse.jetty
jetty-ethereum
diff --git a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java
new file mode 100644
index 000000000000..4ba2bfc367a4
--- /dev/null
+++ b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java
@@ -0,0 +1,217 @@
+//
+// ========================================================================
+// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.docs.programming.server.deploy;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import org.eclipse.jetty.deploy.Deployer;
+import org.eclipse.jetty.deploy.DeploymentScanner;
+import org.eclipse.jetty.deploy.StandardDeployer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.DefaultHandler;
+import org.eclipse.jetty.util.component.Environment;
+import org.eclipse.jetty.xml.EnvironmentBuilder;
+
+@SuppressWarnings("unused")
+public class DeployDocs
+{
+ public void simple() throws Exception
+ {
+ // tag::simple[]
+ Server server = new Server();
+
+ // ContextHandlerCollection is required by the deployer.
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ server.setHandler(contexts);
+
+ // Optional, shows the contexts deployed on the Server.
+ server.setDefaultHandler(new DefaultHandler());
+
+ // Create the deployer.
+ Deployer deployer = new StandardDeployer(contexts);
+
+ // Create the DeploymentScanner to monitor the webapps directory.
+ DeploymentScanner scanner = new DeploymentScanner(server, deployer);
+ scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
+ // Link the lifecycle of the DeploymentScanner to the Server.
+ server.addBean(scanner);
+
+ // Create an environment, with the name of your choice,
+ // and no extra class-path or module-path.
+ EnvironmentBuilder envBuilder = new EnvironmentBuilder("simple");
+ Environment environment = envBuilder.build();
+
+ // Tell the DeploymentScanner about the environment
+ // it should use to deploy web applications.
+ scanner.configureEnvironment(environment.getName());
+
+ server.start();
+ // end::simple[]
+ }
+
+ public void jettyStatic() throws Exception
+ {
+ // tag::static[]
+ Server server = new Server();
+
+ // ContextHandlerCollection is required by the deployer.
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ server.setHandler(contexts);
+
+ // Optional, shows the contexts deployed on the Server.
+ server.setDefaultHandler(new DefaultHandler());
+
+ // Create the deployer.
+ Deployer deployer = new StandardDeployer(contexts);
+
+ // Create the DeploymentScanner to monitor the webapps directory.
+ DeploymentScanner scanner = new DeploymentScanner(server, deployer);
+ scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
+ // Link the lifecycle of the DeploymentScanner to the Server.
+ server.addBean(scanner);
+
+ // Create the static environment.
+ EnvironmentBuilder envBuilder = new EnvironmentBuilder("static");
+ envBuilder.addClassPath("/path/to/jetty-staticapp-{jetty-version}.jar"); // <1>
+ Environment environment = envBuilder.build();
+
+ // Tell the DeploymentScanner about the environment, and configure it for deployment.
+ DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); // <2>
+ envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.staticapp.StaticAppContext");
+
+ server.start();
+ // end::static[]
+ }
+
+ public void jettyCore() throws Exception
+ {
+ // tag::core[]
+ Server server = new Server();
+
+ // ContextHandlerCollection is required by the deployer.
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ server.setHandler(contexts);
+
+ // Optional, shows the contexts deployed on the Server.
+ server.setDefaultHandler(new DefaultHandler());
+
+ // Create the deployer.
+ Deployer deployer = new StandardDeployer(contexts);
+
+ // Create the DeploymentScanner to monitor the webapps directory.
+ DeploymentScanner scanner = new DeploymentScanner(server, deployer);
+ scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
+ // Link the lifecycle of the DeploymentScanner to the Server.
+ server.addBean(scanner);
+
+ // Create the core environment.
+ EnvironmentBuilder envBuilder = new EnvironmentBuilder("core");
+ envBuilder.addClassPath("/path/to/jetty-coreapp-{jetty-version}.jar"); // <1>
+ Environment environment = envBuilder.build();
+
+ // Tell the DeploymentScanner about the environment, and configure it for deployment.
+ DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); // <2>
+ envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext");
+
+ server.start();
+ // end::core[]
+ }
+
+ public void jakarta() throws Exception
+ {
+ // tag::jakarta[]
+ Server server = new Server();
+
+ // ContextHandlerCollection is required by the deployer.
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ server.setHandler(contexts);
+
+ // Optional, shows the contexts deployed on the Server.
+ server.setDefaultHandler(new DefaultHandler());
+
+ // Create the deployer.
+ Deployer deployer = new StandardDeployer(contexts);
+
+ // Create the DeploymentScanner to monitor the webapps directory.
+ DeploymentScanner scanner = new DeploymentScanner(server, deployer);
+ scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
+ // Link the lifecycle of the DeploymentScanner to the Server.
+ server.addBean(scanner);
+
+ // Create the {ee-current} environment.
+ EnvironmentBuilder envBuilder = new EnvironmentBuilder("{ee-current}");
+ envBuilder.addClassPath("/path/to/jakarta.servlet-api-{servlet-current-version}.jar"); // <1>
+ envBuilder.addClassPath("/path/to/jetty-{ee-current}-servlet-{jetty-version}.jar");
+ envBuilder.addClassPath("/path/to/jetty-{ee-current}-webapp-{jetty-version}.jar");
+ Environment environment = envBuilder.build();
+
+ // Tell the DeploymentScanner about the environment, and configure it for deployment.
+ DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName());
+ envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.{ee-current}.webapp.WebAppContext"); // <2>
+ envConfig.setDefaultsDescriptor("/path/to/{ee-current}-default-web.xml"); // <3>
+ // Other relevant Jakarta environment configurations.
+
+ server.start();
+ // end::jakarta[]
+ }
+
+ public void multi() throws Exception
+ {
+ // tag::multi[]
+ Server server = new Server();
+
+ // ContextHandlerCollection is required by the deployer.
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ server.setHandler(contexts);
+
+ // Optional, shows the contexts deployed on the Server.
+ server.setDefaultHandler(new DefaultHandler());
+
+ // Create the deployer.
+ Deployer deployer = new StandardDeployer(contexts);
+
+ // Create the DeploymentScanner to monitor the webapps directory.
+ DeploymentScanner scanner = new DeploymentScanner(server, deployer);
+ scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
+ // Link the lifecycle of the DeploymentScanner to the Server.
+ server.addBean(scanner);
+
+ // Create the core environment.
+ EnvironmentBuilder coreEnvBuilder = new EnvironmentBuilder("core");
+ coreEnvBuilder.addClassPath("/path/to/jetty-coreapp-{jetty-version}.jar");
+ Environment coreEnv = coreEnvBuilder.build();
+
+ // Create the {ee-current} environment.
+ EnvironmentBuilder jakartaEnvBuilder = new EnvironmentBuilder("{ee-current}");
+ jakartaEnvBuilder.addClassPath("/path/to/jakarta.servlet-api-{servlet-current-version}.jar");
+ jakartaEnvBuilder.addClassPath("/path/to/jetty-{ee-current}-servlet-{jetty-version}.jar");
+ jakartaEnvBuilder.addClassPath("/path/to/jetty-{ee-current}-webapp-{jetty-version}.jar");
+ Environment jakartaEnv = jakartaEnvBuilder.build();
+
+ // Tell the DeploymentScanner about the environments, and configure them for deployment.
+
+ DeploymentScanner.EnvironmentConfig coreEnvConfig = scanner.configureEnvironment(coreEnv.getName());
+ coreEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext");
+
+ DeploymentScanner.EnvironmentConfig jakartaEnvConfig = scanner.configureEnvironment(jakartaEnv.getName());
+ jakartaEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.{ee-current}.webapp.WebAppContext");
+ jakartaEnvConfig.setDefaultsDescriptor("/path/to/{ee-current}-default-web.xml");
+ // Other relevant Jakarta environment configurations.
+
+ server.start();
+ // end::multi[]
+ }
+}
diff --git a/documentation/jetty/modules/programming-guide/nav.adoc b/documentation/jetty/modules/programming-guide/nav.adoc
index b7372ea98078..d6085cb76114 100644
--- a/documentation/jetty/modules/programming-guide/nav.adoc
+++ b/documentation/jetty/modules/programming-guide/nav.adoc
@@ -24,6 +24,7 @@
** xref:server/http3.adoc[]
** xref:server/compliance.adoc[]
** xref:server/session.adoc[]
+** xref:server/deploy.adoc[]
** xref:server/websocket.adoc[]
** xref:server/fastcgi.adoc[]
** xref:server/io-arch.adoc[]
diff --git a/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc b/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc
new file mode 100644
index 000000000000..1ed7e1ffd83a
--- /dev/null
+++ b/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc
@@ -0,0 +1,210 @@
+//
+// ========================================================================
+// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+= Web Application Deployment
+
+When using the xref:server/index.adoc[Jetty server libraries] in your code, web applications are typically assembled by composing the required ``Handler``s, as explained in xref:server/http.adoc#handler[this section].
+
+When the `Server` instance is started, web applications are also started; there typically is no deployer component that can deploy web applications after the `Server` instance is started.
+
+The deployer component is the key component to deploy web applications when using Jetty as a standalone server, and it is detailed xref:operations-guide:deploy/index.adoc[here].
+
+However, it is possible to use the Jetty server libraries in your code with the deployer component, so that you can deploy web applications after the `Server` instance is started.
+
+The Maven artifact coordinates are:
+
+[,xml,subs=attributes+]
+----
+
+ org.eclipse.jetty
+ jetty-deploy
+ {jetty-version}
+
+----
+
+The main components to set up are:
+
+* A `Deployer`, by default `org.eclipse.jetty.deploy.StandardDeployer`.
+The deployer component is responsible for adding and removing a `ContextHandler` (or subclass) instance, that represents a web application, from the `Handler` tree, and is responsible for the lifecycle (starting and stopping) the `ContextHandler`.
+* A `DeploymentScanner`, that scans directories for files or directories that represent web applications.
+Typical web application files are `+*.war+`, `+*.properties+` and `+*.xml+` files.
+When a web application file or directory is added/updated/removed, `DeploymentScanner` creates or retrieves (depending on the event) the corresponding `ContextHandler` and calls the `Deployer` to deploy/redeploy/undeploy the web application.
+
+[plantuml]
+----
+skinparam backgroundColor transparent
+skinparam monochrome true
+skinparam shadowing false
+
+participant WebDir as "Web Application Directory"
+participant DeploymentScanner
+participant Deployer
+participant ContextHandlerCollection
+
+DeploymentScanner -> WebDir : monitors for changes
+-> WebDir : create webapp.war
+DeploymentScanner -> Deployer : deploy ContextHandler
+Deployer -> ContextHandlerCollection : deployHandler() + start
+-> WebDir : delete webapp.war
+DeploymentScanner -> Deployer : undeploy ContextHandler
+Deployer -> ContextHandlerCollection : stop + removeHandler()
+----
+
+Each web application is deployed to a specific _environment_.
+
+The environment allows you to specify environmental properties that will be available to all web applications, as well as a `ClassLoader` that loads classes that are specific to the environment.
+
+Furthermore, the environment determines how the web application file should be interpreted: if it is a directory, whether it should be interpreted as a xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web application], or as a xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web application], or as a xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta EE exploded `+*.war+`].
+
+By default, there are no environments; you must always create at least one, depending on the type of deployment you want for your web applications.
+
+[[simple]]
+== Simple Deployer Setup
+
+The simplest deployer setup is when you deploy a web application via xref:operations-guide:deploy/index.adoc#context-xml[Jetty context XML file]:
+
+[,java,indent=0]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=simple]
+----
+
+With this simple setup, you can only deploy Jetty context XML files.
+In the Jetty context XML files, you can only reference classes that you have in the class-path or module-path, for example:
+
+.acme-webapp.xml
+[,xml]
+----
+
+
+ /acme
+
+
+
+
+----
+<1> This class must be in the class-path or module-path.
+
+WARNING: Do not be tempted to use this simple setup to deploy Jetty Core web applications, Jetty Static web applications, or Jakarta web applications; their setup is described their respective sections below.
+
+[[static]]
+== Jetty Static Deployer Setup
+
+For xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web applications], the setup is the following:
+
+[,java,indent=0,subs=+attributes]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=static]
+----
+<1> The environment is configured with its own class-path.
+<2> Jetty Static web applications use `StaticAppContext` as their `ContextHandler`, so web application directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web application format].
+
+Your Jetty Static web application is a directory, for example `acme-asset/`, under `/path/to/webapps/`:
+
+[,bash]
+----
+/path/to/webapps/
+└── acme-assets/
+ ├── css/
+ │ └── styles.css
+ └── index.html
+----
+
+[[core]]
+== Jetty Core Deployer Setup
+
+For xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web applications], the setup is the following:
+
+[,java,indent=0,subs=+attributes]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=core]
+----
+<1> The environment is configured with its own class-path.
+<2> Jetty Core web applications use `CoreAppContext` as their `ContextHandler`, so web application directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web application format].
+
+Your Jetty Core web application is a directory, for example `acme-core-app/` under `/path/to/webapps/`:
+
+[,bash]
+----
+/path/to/webapps/
+└── acme-core-app/
+ ├── static # Static files are served from this directory.
+ │ └── favicon.ico
+ ├── classes # Where web application Java classes reside.
+ │ └── com
+ │ └── acme
+ │ └── AcmeHandler.class
+ ├── lib # Where web application Java libraries reside.
+ │ └── acme-util.jar
+ └── jetty-web.xml # Web application specific configuration.
+----
+
+With this setup you have the following class loader hierarchy, with the standard _parent first_ model for class loading:
+
+[,bash,subs=+attributes]
+----
+System ClassLoader # jetty-server-{jetty-version}.jar, etc.
+└── Environment ClassLoader # jetty-coreapp-{jetty-version}.jar
+ └── Jetty Core App ClassLoader # acme-core-app/classes/:acme-core-app/lib/acme-util.jar
+----
+
+[[jakarta]]
+== Jakarta Deployer Setup
+
+For xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta web applications], the setup is the following:
+
+[,java,indent=0,subs=+attributes]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=jakarta]
+----
+<1> The environment is configured with its own class-path, that includes the Servlet API `+*.jar+` and the Jetty implementation `+*.jar+`s of the Servlet APIs.
+<2> Jakarta web applications use `WebAppContext` as their `ContextHandler`, so web application `+*.war+` files or directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta web application format].
+
+Your Jakarta web application is a `+*.war+` file, for example `acme.war` under `/path/to/webapps/`:
+
+[,bash]
+----
+/path/to/webapps/
+└── acme.war
+----
+
+With this setup you have the following class loader hierarchy, with the standard Jakarta _web application first_ model for class loading:
+
+[,bash,subs=+attributes]
+----
+System ClassLoader # jetty-server-{jetty-version}.jar: etc.
+└── Environment ClassLoader # jakarta.servlet-api-{servlet-current-version}.jar: etc.
+ └── Jakarta Web App ClassLoader # acme.war!/WEB-INF/classes/:acme.war!/WEB-INF/lib/*.jar
+----
+
+[[multi]]
+== Multiple Environments
+
+If you need to deploy web applications to different environments, for example `core` and `{ee-current}`, the setup is the following:
+
+[,java,indent=0,subs=+attributes]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=multi]
+----
+
+The class loader hierarchy is the following:
+
+[,bash,subs=+attributes]
+----
+System ClassLoader
+├── core Environment ClassLoader
+│ └── Jetty Core App ClassLoader
+└── ee11 Environment ClassLoader
+ └── Jakarta Web App ClassLoader
+----
+
+With multiple environments, it is good practice to specify the web application `+*.properties+` file, as described in xref:operations-guide:deploy/index.adoc#web-application-files[this section].