ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 1 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://quarkus.io/guides/command-mode-reference |
| Last Crawled | 2026-03-08 16:44:19 (29 days ago) |
| First Indexed | 2020-05-01 07:28:27 (5 years ago) |
| HTTP Status Code | 200 |
| Meta Title | Command Mode Applications - Quarkus |
| Meta Description | Quarkus: Supersonic Subatomic Java |
| Meta Canonical | null |
| Boilerpipe Text | Edit this Page
This reference covers how to write applications that run and then exit.
Solution
We recommend that you follow the instructions in the next sections and create the application step by step.
However, you can go right to the completed example.
The solution is located in the
getting-started-command-mode
directory
.
Creating the Maven project
First, we need to create a new Quarkus project with the following command:
For Windows users:
If using cmd, (don’t use backward slash
\
and put everything on the same line)
If using Powershell, wrap
-D
parameters in double quotes e.g.
"-DprojectArtifactId=command-mode-quickstart"
The suggested project creation command lines disable the codestarts to avoid including a REST server. Similarly, if you use code.quarkus.io to generate a
project, you need to go to
MORE OPTIONS → Starter Code
and select
No
to avoid adding the Quarkus REST (formerly RESTEasy Reactive) extension.
The Quarkus REST extension is added automatically only if you ask for codestarts and you didn’t specify any extensions.
Writing Command Mode Applications
There are two different approaches that can be used to implement applications
that exit.
Implement
QuarkusApplication
and have Quarkus run this method automatically
Implement
QuarkusApplication
and a Java main method, and use the Java main method to launch Quarkus
In this document the
QuarkusApplication
instance is referred to as the application main,
and a class with a Java main method is the Java main.
The simplest possible command mode application with access to Quarkus APIs might appear as follows:
import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain
(1)
public class HelloWorldMain implements QuarkusApplication {
@Override
public int run(String... args) throws Exception {
(2)
System.out.println("Hello " + args[0]);
return 0;
}
}
1
The
@QuarkusMain
annotation tells Quarkus that this is the main entry point.
2
The
run
method is invoked once Quarkus starts, and the application stops when it finishes.
Main method
If we want to use a Java main to run the application main it would look like:
import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain
public class JavaMain {
public static void main(String... args) {
Quarkus.run(HelloWorldMain.class, args);
}
}
This is effectively the same as running the
HelloWorldMain
application main directly, but has the advantage it can
be run from the IDE.
If a class that implements
QuarkusApplication
and has a Java main then the Java main will be run.
It is recommended that a Java main perform very little logic, and just
launch the application main. In development mode the Java main will run in a
different ClassLoader to the main application, so may not behave as you would
expect.
Multiple Main Methods
It is possible to have multiple main methods in an application, and select between them at build time.
The
@QuarkusMain
annotation takes an optional 'name' parameter, and this can be used to select the
main to run using the
quarkus.package.main-class
build time configuration option. If you don’t want
to use annotations this can also be used to specify the fully qualified name of a main class.
By default, the
@QuarkusMain
with no name (i.e. the empty string) will be used, and if it is not present
and
quarkus.package.main-class
is not specified then Quarkus will automatically generate a main class
that just runs the application.
The
name
of
@QuarkusMain
must be unique (including the default of the empty string). If you
have multiple
@QuarkusMain
annotations in your application the build will fail if the names are not
unique.
The command mode lifecycle
When running a command mode application the basic lifecycle is as follows:
Start Quarkus
Run the
QuarkusApplication
main method
Shut down Quarkus and exit the JVM after the main method returns
Shutdown is always initiated by the application main thread returning. If you want to run some logic on startup,
and then run like a normal application (i.e. not exit) then you should call
Quarkus.waitForExit
from the main
thread (A non-command mode application is essentially just running an application that just calls
waitForExit
).
If you want to shut down a running application and you are not in the main thread, then you should call
Quarkus.asyncExit
in order to unblock the main thread and initiate the shutdown process.
Running the application
To run the command mode application on the JVM, first build it using
mvnw package
or equivalent.
Then launch it:
java -jar target/quarkus-app/quarkus-run.jar
You can also build a native application with
mvnw package -Dnative
, and launch it with something like:
./target/getting-started-command-mode-1.0-SNAPSHOT-runner
Development Mode
Also, for command mode applications, the dev mode is supported.
When you start your application in dev mode, the command mode application is executed:
CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev
As command mode applications will often require arguments to be passed on the command line, this is also possible in dev mode:
CLI
quarkus dev '--help'
Maven
./mvnw quarkus:dev -Dquarkus.args='--help'
Gradle
./gradlew quarkusDev --quarkus-args='--help'
You should see the following down the bottom of the screen after the application is stopped:
--
Press [space] to restart, [e] to edit command line args (currently '-w --tags 1.0.1.Final'), [r] to resume testing, [o] Toggle test output, [h] for more options>
You can press the
Space bar
key and the application will be started again.
You can also use the
e
hotkey to edit the command line arguments and restart your application.
Testing Command Mode Applications
Command Mode applications can be tested using the
@QuarkusMainTest
and
@QuarkusMainIntegrationTest
annotations. These
work in a similar way to
@QuarkusTest
and
@QuarkusIntegrationTest
where
@QuarkusMainTest
will run the CLI tests
within the current JVM, while
QuarkusIntegrationTest
is used to run the generated executable (both jars and native).
We can write a simple test for our CLI application above as follows:
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainLauncher;
import io.quarkus.test.junit.main.QuarkusMainTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusMainTest
public class HelloTest {
@Test
@Launch("World")
public void testLaunchCommand(LaunchResult result) {
Assertions.assertTrue(result.getOutput().contains("Hello World"));
}
@Test
@Launch(value = {}, exitCode = 1)
public void testLaunchCommandFailed() {
}
@Test
public void testManualLaunch(QuarkusMainLauncher launcher) {
LaunchResult result = launcher.launch("Everyone");
Assertions.assertEquals(0, result.exitCode());
Assertions.assertTrue(result.getOutput().contains("Hello Everyone"));
}
}
Each test method must be annotated with
@Launch
to automatically start the application or have a
QuarkusMainLauncher
parameter to manually launch the application.
We can then extend this with an integration test that can be used to test the native executable or runnable jar:
import io.quarkus.test.junit.main.QuarkusMainIntegrationTest;
@QuarkusMainIntegrationTest
public class HelloIT extends HelloTest {
}
Limitations
@QuarkusMainTest
does
not
support the following features:
Injection of CDI beans
Using Panache entities
Using mocks with
@InjectMock
Usually, it’s best to use a combination of
@QuarkusMainTest
tests for testing application externals, and
@QuarkusTest
tests for fine-grained testing which requires access to application internals.
Mocking
CDI injection is not supported in the
@QuarkusMainTest
tests.
Consequently, mocking CDI beans with
QuarkusMock
or
@InjectMock
is not supported either.
It is possible to mock CDI beans by leveraging
test profiles
though.
For instance, in the following test, the launched application would receive a mocked singleton
CdiBean1
. The implementation
MockedCdiBean1
is provided by the test:
package org.acme.commandmode.test;
import java.util.Set;
import jakarta.enterprise.inject.Alternative;
import jakarta.inject.Singleton;
import org.junit.jupiter.api.Test;
import org.acme.commandmode.test.MyCommandModeTest.MyTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainTest;
@QuarkusMainTest
@TestProfile(MyTestProfile.class)
public class MyCommandModeTest {
@Test
@Launch(value = {})
public void testLaunchCommand(LaunchResult result) {
// ... assertions ...
}
public static class MyTestProfile implements QuarkusTestProfile {
@Override
public Set<Class<?>> getEnabledAlternatives() {
return Set.of(MockedCdiBean1.class);
(1)
}
}
@Alternative
(2)
@Singleton
(3)
public static class MockedCdiBean1 implements CdiBean1 {
@Override
public String myMethod() {
return "mocked value";
}
}
}
1
List all the CDI beans for which you want to enable an alternative mocked bean.
2
Use
@Alternative
without a
@Priority
. Make sure you don’t use
@Mock
.
3
The scope of the mocked bean should be consistent with the original one.
Using this pattern, you can enable specific alternatives for any given test. |
| Markdown | [](https://quarkus.io/)
- Why
- [WHAT IS QUARKUS?](https://quarkus.io/about)
- [DEVELOPER JOY](https://quarkus.io/developer-joy)
- [PERFORMANCE](https://quarkus.io/performance)
- [KUBERNETES NATIVE](https://quarkus.io/kubernetes-native)
- [STANDARDS](https://quarkus.io/standards)
- [VERSATILITY](https://quarkus.io/versatility)
- [CONTAINER FIRST](https://quarkus.io/container-first)
- [USING SPRING?](https://quarkus.io/spring)
- AI
- [AI OVERVIEW](https://quarkus.io/ai)
- [JAVA FOR AI](https://quarkus.io/java-for-ai)
- [WHY QUARKUS FOR AI](https://quarkus.io/quarkus-for-ai)
- [AI BLUEPRINTS](https://quarkus.io/ai-blueprints)
- Learn
- [GET STARTED](https://quarkus.io/get-started)
- [DOCUMENTATION](https://quarkus.io/guides)
- [USER STORIES](https://quarkus.io/userstories/)
- ["Q" TIP VIDEOS](https://quarkus.io/qtips)
- [BOOKS](https://quarkus.io/books)
- Extensions
- [BROWSE EXTENSIONS](https://quarkus.io/extensions/)
- [USE EXTENSIONS](https://quarkus.io/faq/#what-is-a-quarkus-extension)
- [CREATE EXTENSIONS](https://quarkus.io/guides/writing-extensions)
- [SHARE EXTENSIONS](https://hub.quarkiverse.io/)
- Community
- [SUPPORT](https://quarkus.io/support/)
- [BLOG](https://quarkus.io/blog)
- [DISCUSSION](https://quarkus.io/discussion)
- [WORKING GROUPS](https://quarkus.io/working-groups)
- [PODCAST](https://quarkus.io/insights)
- [EVENTS](https://quarkus.io/events)
- [NEWSLETTER](https://quarkus.io/newsletter)
- [ROADMAP](https://github.com/orgs/quarkusio/projects/13/views/1)
- [BENEFACTORS](https://quarkus.io/benefactors)
- [START CODING](https://code.quarkus.io/)
- - [OFFICIAL (ENGLISH)](https://quarkus.io/guides/command-mode-reference)
- [PORTUGUĂŠS (BR)](https://pt.quarkus.io/guides/command-mode-reference)
- [ESPAÑOL](https://es.quarkus.io/guides/command-mode-reference)
- [简体ä¸ć–‡](https://cn.quarkus.io/guides/command-mode-reference)
- [日本語](https://ja.quarkus.io/guides/command-mode-reference)
[Back to Guides](https://quarkus.io/guides/)
By Version
[Edit this Page](https://github.com/quarkusio/quarkus/edit/main/docs/src/main/asciidoc/command-mode-reference.adoc)
# Command Mode Applications
This reference covers how to write applications that run and then exit.
## Solution
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
Clone the Git repository: `git clone <https://github.com/quarkusio/quarkus-quickstarts.git>`, or download an [archive](https://github.com/quarkusio/quarkus-quickstarts/archive/main.zip).
The solution is located in the `getting-started-command-mode` [directory](https://github.com/quarkusio/quarkus-quickstarts/tree/main/getting-started-command-mode).
## Creating the Maven project
First, we need to create a new Quarkus project with the following command:
CLI
```
quarkus create app org.acme:command-mode-quickstart \
--no-code
cd command-mode-quickstart
```
To create a Gradle project, add the `--gradle` or `--gradle-kotlin-dsl` option.
For more information about how to install and use the Quarkus CLI, see the [Quarkus CLI](https://quarkus.io/guides/cli-tooling) guide.
Maven
```
mvn io.quarkus.platform:quarkus-maven-plugin:3.32.2:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=command-mode-quickstart \
-DnoCode
cd command-mode-quickstart
```
To create a Gradle project, add the `-DbuildTool=gradle` or `-DbuildTool=gradle-kotlin-dsl` option.
For Windows users:
- If using cmd, (don’t use backward slash `\` and put everything on the same line)
- If using Powershell, wrap `-D` parameters in double quotes e.g. `"-DprojectArtifactId=command-mode-quickstart"`
| | |
|---|---|
| | The suggested project creation command lines disable the codestarts to avoid including a REST server. Similarly, if you use code.quarkus.io to generate a project, you need to go to **MORE OPTIONS → Starter Code** and select **No** to avoid adding the Quarkus REST (formerly RESTEasy Reactive) extension. |
The Quarkus REST extension is added automatically only if you ask for codestarts and you didn’t specify any extensions.
## Writing Command Mode Applications
There are two different approaches that can be used to implement applications that exit.
1. Implement `QuarkusApplication` and have Quarkus run this method automatically
2. Implement `QuarkusApplication` and a Java main method, and use the Java main method to launch Quarkus
In this document the `QuarkusApplication` instance is referred to as the application main, and a class with a Java main method is the Java main.
The simplest possible command mode application with access to Quarkus APIs might appear as follows:
```
import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain (1)
public class HelloWorldMain implements QuarkusApplication {
@Override
public int run(String... args) throws Exception { (2)
System.out.println("Hello " + args[0]);
return 0;
}
}
```
| | |
|---|---|
| **1** | The `@QuarkusMain` annotation tells Quarkus that this is the main entry point. |
| **2** | The `run` method is invoked once Quarkus starts, and the application stops when it finishes. |
### Contexts
Got a `ContextNotActiveException`?
A command mode application (like a CLI) is a bit different from say an HTTP service, there is a single call from the command line. So the notion of *request* let alone multiple requests does not exist per se. Therefore, request scope is not the default.
To get access to your application beans and services, be aware that a `@QuarkusMain` instance is an application scoped bean by default. It has access to singletons, application and dependent scoped beans.
If you want to interact with beans that requires a request scope, simply add the `@ActivateRequestContext` annotation on your `run()` method. This let `run()` have access to methods like `listAll()` and `query*` methods on a Panache Entity. Without it, you will eventually get a `ContextNotActiveException` when accessing such classes/beans.
### Main method
If we want to use a Java main to run the application main it would look like:
```
import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain
public class JavaMain {
public static void main(String... args) {
Quarkus.run(HelloWorldMain.class, args);
}
}
```
This is effectively the same as running the `HelloWorldMain` application main directly, but has the advantage it can be run from the IDE.
| | |
|---|---|
| | If a class that implements `QuarkusApplication` and has a Java main then the Java main will be run. |
| | |
|---|---|
| | It is recommended that a Java main perform very little logic, and just launch the application main. In development mode the Java main will run in a different ClassLoader to the main application, so may not behave as you would expect. |
#### Multiple Main Methods
It is possible to have multiple main methods in an application, and select between them at build time. The `@QuarkusMain` annotation takes an optional 'name' parameter, and this can be used to select the main to run using the `quarkus.package.main-class` build time configuration option. If you don’t want to use annotations this can also be used to specify the fully qualified name of a main class.
By default, the `@QuarkusMain` with no name (i.e. the empty string) will be used, and if it is not present and `quarkus.package.main-class` is not specified then Quarkus will automatically generate a main class that just runs the application.
| | |
|---|---|
| | The `name` of `@QuarkusMain` must be unique (including the default of the empty string). If you have multiple `@QuarkusMain` annotations in your application the build will fail if the names are not unique. |
### The command mode lifecycle
When running a command mode application the basic lifecycle is as follows:
1. Start Quarkus
2. Run the `QuarkusApplication` main method
3. Shut down Quarkus and exit the JVM after the main method returns
Shutdown is always initiated by the application main thread returning. If you want to run some logic on startup, and then run like a normal application (i.e. not exit) then you should call `Quarkus.waitForExit` from the main thread (A non-command mode application is essentially just running an application that just calls `waitForExit`).
If you want to shut down a running application and you are not in the main thread, then you should call `Quarkus.asyncExit` in order to unblock the main thread and initiate the shutdown process.
### Running the application
To run the command mode application on the JVM, first build it using `mvnw package` or equivalent.
Then launch it:
```
java -jar target/quarkus-app/quarkus-run.jar
```
You can also build a native application with `mvnw package -Dnative`, and launch it with something like:
```
./target/getting-started-command-mode-1.0-SNAPSHOT-runner
```
### Development Mode
Also, for command mode applications, the dev mode is supported. When you start your application in dev mode, the command mode application is executed:
CLI
```
quarkus dev
```
Maven
```
./mvnw quarkus:dev
```
Gradle
```
./gradlew --console=plain quarkusDev
```
As command mode applications will often require arguments to be passed on the command line, this is also possible in dev mode:
CLI
```
quarkus dev '--help'
```
Maven
```
./mvnw quarkus:dev -Dquarkus.args='--help'
```
Gradle
```
./gradlew quarkusDev --quarkus-args='--help'
```
You should see the following down the bottom of the screen after the application is stopped:
```
--
Press [space] to restart, [e] to edit command line args (currently '-w --tags 1.0.1.Final'), [r] to resume testing, [o] Toggle test output, [h] for more options>
```
You can press the `Space bar` key and the application will be started again. You can also use the `e` hotkey to edit the command line arguments and restart your application.
## Testing Command Mode Applications
Command Mode applications can be tested using the `@QuarkusMainTest` and `@QuarkusMainIntegrationTest` annotations. These work in a similar way to `@QuarkusTest` and `@QuarkusIntegrationTest` where `@QuarkusMainTest` will run the CLI tests within the current JVM, while `QuarkusIntegrationTest` is used to run the generated executable (both jars and native).
We can write a simple test for our CLI application above as follows:
```
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainLauncher;
import io.quarkus.test.junit.main.QuarkusMainTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusMainTest
public class HelloTest {
@Test
@Launch("World")
public void testLaunchCommand(LaunchResult result) {
Assertions.assertTrue(result.getOutput().contains("Hello World"));
}
@Test
@Launch(value = {}, exitCode = 1)
public void testLaunchCommandFailed() {
}
@Test
public void testManualLaunch(QuarkusMainLauncher launcher) {
LaunchResult result = launcher.launch("Everyone");
Assertions.assertEquals(0, result.exitCode());
Assertions.assertTrue(result.getOutput().contains("Hello Everyone"));
}
}
```
Each test method must be annotated with `@Launch` to automatically start the application or have a `QuarkusMainLauncher` parameter to manually launch the application.
We can then extend this with an integration test that can be used to test the native executable or runnable jar:
```
import io.quarkus.test.junit.main.QuarkusMainIntegrationTest;
@QuarkusMainIntegrationTest
public class HelloIT extends HelloTest {
}
```
### Limitations
`@QuarkusMainTest` does **not** support the following features:
- Injection of CDI beans
- Using Panache entities
- Using mocks with `@InjectMock`
Usually, it’s best to use a combination of `@QuarkusMainTest` tests for testing application externals, and `@QuarkusTest` tests for fine-grained testing which requires access to application internals.
#### Mocking
CDI injection is not supported in the `@QuarkusMainTest` tests. Consequently, mocking CDI beans with `QuarkusMock` or `@InjectMock` is not supported either.
It is possible to mock CDI beans by leveraging [test profiles](https://quarkus.io/guides/getting-started-testing#testing_different_profiles) though.
For instance, in the following test, the launched application would receive a mocked singleton `CdiBean1`. The implementation `MockedCdiBean1` is provided by the test:
```
package org.acme.commandmode.test;
import java.util.Set;
import jakarta.enterprise.inject.Alternative;
import jakarta.inject.Singleton;
import org.junit.jupiter.api.Test;
import org.acme.commandmode.test.MyCommandModeTest.MyTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainTest;
@QuarkusMainTest
@TestProfile(MyTestProfile.class)
public class MyCommandModeTest {
@Test
@Launch(value = {})
public void testLaunchCommand(LaunchResult result) {
// ... assertions ...
}
public static class MyTestProfile implements QuarkusTestProfile {
@Override
public Set<Class<?>> getEnabledAlternatives() {
return Set.of(MockedCdiBean1.class); (1)
}
}
@Alternative (2)
@Singleton (3)
public static class MockedCdiBean1 implements CdiBean1 {
@Override
public String myMethod() {
return "mocked value";
}
}
}
```
| | |
|---|---|
| **1** | List all the CDI beans for which you want to enable an alternative mocked bean. |
| **2** | Use `@Alternative` without a `@Priority`. Make sure you don’t use `@Mock`. |
| **3** | The scope of the mocked bean should be consistent with the original one. |
Using this pattern, you can enable specific alternatives for any given test.
- [Solution](https://quarkus.io/guides/command-mode-reference#solution)
- [Creating the Maven project](https://quarkus.io/guides/command-mode-reference#creating-the-maven-project)
- [Writing Command Mode Applications](https://quarkus.io/guides/command-mode-reference#writing-command-mode-applications)
- [Contexts](https://quarkus.io/guides/command-mode-reference#contexts)
- [Main method](https://quarkus.io/guides/command-mode-reference#main-method)
- [The command mode lifecycle](https://quarkus.io/guides/command-mode-reference#the-command-mode-lifecycle)
- [Running the application](https://quarkus.io/guides/command-mode-reference#running-the-application)
- [Development Mode](https://quarkus.io/guides/command-mode-reference#development-mode)
- [Testing Command Mode Applications](https://quarkus.io/guides/command-mode-reference#testing-command-mode-applications)
- [Limitations](https://quarkus.io/guides/command-mode-reference#limitations)
## Related content
### On the same topics
- [Command Mode with Picocli](https://quarkus.io/guides/picocli)
- [Building Quarkus apps with Quarkus Command Line Interface (CLI)](https://quarkus.io/guides/cli-tooling)
- [Using gRPC CLI](https://quarkus.io/guides/grpc-cli)
[](https://quarkus.io/)
Quarkus is open. All dependencies of this project are available under the [Apache Software License 2.0](https://www.apache.org/licenses/LICENSE-2.0) or compatible license. [CC by 3.0](https://creativecommons.org/licenses/by/3.0/)
This website was built with [Jekyll](https://jekyllrb.com/), is hosted on [GitHub Pages](https://pages.github.com/) and is completely open source. If you want to make it better, [fork the website](https://github.com/quarkusio/quarkusio.github.io) and show us what you’ve got.
Navigation
- [Home](https://quarkus.io/)
- [About](https://quarkus.io/about)
- [Blog](https://quarkus.io/blog)
- [Podcast](https://quarkus.io/insights)
- [Events](https://quarkus.io/events)
- [Newsletter](https://quarkus.io/newsletter)
- [User Stories](https://quarkus.io/userstories)
- [Roadmap](https://github.com/orgs/quarkusio/projects/13/views/1)
- [Security policy](https://quarkus.io/security)
- [Usage](https://quarkus.io/usage)
- [Brand](https://github.com/commonhaus/artwork/tree/main/projects/quarkus)
- [Wallpapers](https://quarkus.io/desktopwallpapers)
- [Privacy Policy](https://www.redhat.com/en/about/privacy-policy)
Follow Us
- [X](https://x.com/quarkusio)
- [Bluesky](https://bsky.app/profile/quarkus.io)
- [Mastodon](https://fosstodon.org/@quarkusio)
- [Threads](https://www.threads.com/@quarkusio)
- [Facebook](https://www.facebook.com/quarkusio)
- [Linkedin](https://www.linkedin.com/company/quarkusio/)
- [Youtube](https://www.youtube.com/channel/UCaW8QG_QoIk_FnjLgr5eOqg)
- [GitHub](https://github.com/quarkusio)
Get Help
- [Support](https://quarkus.io/support)
- [Guides](https://quarkus.io/guides)
- [FAQ](https://quarkus.io/faq)
- [Get Started](https://quarkus.io/get-started)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/quarkus)
- [Discussions](https://github.com/quarkusio/quarkus/discussions)
- [Development mailing list](https://groups.google.com/forum/#!forum/quarkus-dev)
- [Quarkus Service Status](https://stats.uptimerobot.com/ze1PfweT2p)
Languages
- [English](https://quarkus.io/)
- [PortuguĂŞs (Brasileiro)](https://pt.quarkus.io/)
- [Español](https://es.quarkus.io/)
- [简体ä¸ć–‡](https://cn.quarkus.io/)
- [日本語](https://ja.quarkus.io/)
Quarkus is made of community projects
- [Eclipse Vert.x](https://vertx.io/)
- [SmallRye](https://smallrye.io/)
- [Hibernate](https://hibernate.org/)
- [Netty](https://netty.io/)
- [RESTEasy](https://resteasy.github.io/)
- [Apache Camel](https://camel.apache.org/)
- [Eclipse MicroProfile](https://microprofile.io/)
- [And many more...](https://code.quarkus.io/)
[](https://www.commonhaus.org/)
Copyright © Quarkus. All rights reserved. For details on our trademarks, please visit our [Trademark Policy](https://www.commonhaus.org/policies/trademark-policy/) and [Trademark List](https://www.commonhaus.org/trademarks/). Trademarks of third parties are owned by their respective holders and their mention here does not suggest any endorsement or association. |
| Readable Markdown | [Edit this Page](https://github.com/quarkusio/quarkus/edit/main/docs/src/main/asciidoc/command-mode-reference.adoc)
This reference covers how to write applications that run and then exit.
## Solution
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
The solution is located in the `getting-started-command-mode` [directory](https://github.com/quarkusio/quarkus-quickstarts/tree/main/getting-started-command-mode).
## Creating the Maven project
First, we need to create a new Quarkus project with the following command:
For Windows users:
- If using cmd, (don’t use backward slash `\` and put everything on the same line)
- If using Powershell, wrap `-D` parameters in double quotes e.g. `"-DprojectArtifactId=command-mode-quickstart"`
| | |
|---|---|
| | The suggested project creation command lines disable the codestarts to avoid including a REST server. Similarly, if you use code.quarkus.io to generate a project, you need to go to **MORE OPTIONS → Starter Code** and select **No** to avoid adding the Quarkus REST (formerly RESTEasy Reactive) extension. |
The Quarkus REST extension is added automatically only if you ask for codestarts and you didn’t specify any extensions.
## Writing Command Mode Applications
There are two different approaches that can be used to implement applications that exit.
1. Implement `QuarkusApplication` and have Quarkus run this method automatically
2. Implement `QuarkusApplication` and a Java main method, and use the Java main method to launch Quarkus
In this document the `QuarkusApplication` instance is referred to as the application main, and a class with a Java main method is the Java main.
The simplest possible command mode application with access to Quarkus APIs might appear as follows:
```
import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain (1)
public class HelloWorldMain implements QuarkusApplication {
@Override
public int run(String... args) throws Exception { (2)
System.out.println("Hello " + args[0]);
return 0;
}
}
```
| | |
|---|---|
| **1** | The `@QuarkusMain` annotation tells Quarkus that this is the main entry point. |
| **2** | The `run` method is invoked once Quarkus starts, and the application stops when it finishes. |
### Main method
If we want to use a Java main to run the application main it would look like:
```
import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.annotations.QuarkusMain;
@QuarkusMain
public class JavaMain {
public static void main(String... args) {
Quarkus.run(HelloWorldMain.class, args);
}
}
```
This is effectively the same as running the `HelloWorldMain` application main directly, but has the advantage it can be run from the IDE.
| | |
|---|---|
| | If a class that implements `QuarkusApplication` and has a Java main then the Java main will be run. |
| | |
|---|---|
| | It is recommended that a Java main perform very little logic, and just launch the application main. In development mode the Java main will run in a different ClassLoader to the main application, so may not behave as you would expect. |
#### Multiple Main Methods
It is possible to have multiple main methods in an application, and select between them at build time. The `@QuarkusMain` annotation takes an optional 'name' parameter, and this can be used to select the main to run using the `quarkus.package.main-class` build time configuration option. If you don’t want to use annotations this can also be used to specify the fully qualified name of a main class.
By default, the `@QuarkusMain` with no name (i.e. the empty string) will be used, and if it is not present and `quarkus.package.main-class` is not specified then Quarkus will automatically generate a main class that just runs the application.
| | |
|---|---|
| | The `name` of `@QuarkusMain` must be unique (including the default of the empty string). If you have multiple `@QuarkusMain` annotations in your application the build will fail if the names are not unique. |
### The command mode lifecycle
When running a command mode application the basic lifecycle is as follows:
1. Start Quarkus
2. Run the `QuarkusApplication` main method
3. Shut down Quarkus and exit the JVM after the main method returns
Shutdown is always initiated by the application main thread returning. If you want to run some logic on startup, and then run like a normal application (i.e. not exit) then you should call `Quarkus.waitForExit` from the main thread (A non-command mode application is essentially just running an application that just calls `waitForExit`).
If you want to shut down a running application and you are not in the main thread, then you should call `Quarkus.asyncExit` in order to unblock the main thread and initiate the shutdown process.
### Running the application
To run the command mode application on the JVM, first build it using `mvnw package` or equivalent.
Then launch it:
```
java -jar target/quarkus-app/quarkus-run.jar
```
You can also build a native application with `mvnw package -Dnative`, and launch it with something like:
```
./target/getting-started-command-mode-1.0-SNAPSHOT-runner
```
### Development Mode
Also, for command mode applications, the dev mode is supported. When you start your application in dev mode, the command mode application is executed:
CLI
```
quarkus dev
```
Maven
```
./mvnw quarkus:dev
```
Gradle
```
./gradlew --console=plain quarkusDev
```
As command mode applications will often require arguments to be passed on the command line, this is also possible in dev mode:
CLI
```
quarkus dev '--help'
```
Maven
```
./mvnw quarkus:dev -Dquarkus.args='--help'
```
Gradle
```
./gradlew quarkusDev --quarkus-args='--help'
```
You should see the following down the bottom of the screen after the application is stopped:
```
--
Press [space] to restart, [e] to edit command line args (currently '-w --tags 1.0.1.Final'), [r] to resume testing, [o] Toggle test output, [h] for more options>
```
You can press the `Space bar` key and the application will be started again. You can also use the `e` hotkey to edit the command line arguments and restart your application.
## Testing Command Mode Applications
Command Mode applications can be tested using the `@QuarkusMainTest` and `@QuarkusMainIntegrationTest` annotations. These work in a similar way to `@QuarkusTest` and `@QuarkusIntegrationTest` where `@QuarkusMainTest` will run the CLI tests within the current JVM, while `QuarkusIntegrationTest` is used to run the generated executable (both jars and native).
We can write a simple test for our CLI application above as follows:
```
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainLauncher;
import io.quarkus.test.junit.main.QuarkusMainTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusMainTest
public class HelloTest {
@Test
@Launch("World")
public void testLaunchCommand(LaunchResult result) {
Assertions.assertTrue(result.getOutput().contains("Hello World"));
}
@Test
@Launch(value = {}, exitCode = 1)
public void testLaunchCommandFailed() {
}
@Test
public void testManualLaunch(QuarkusMainLauncher launcher) {
LaunchResult result = launcher.launch("Everyone");
Assertions.assertEquals(0, result.exitCode());
Assertions.assertTrue(result.getOutput().contains("Hello Everyone"));
}
}
```
Each test method must be annotated with `@Launch` to automatically start the application or have a `QuarkusMainLauncher` parameter to manually launch the application.
We can then extend this with an integration test that can be used to test the native executable or runnable jar:
```
import io.quarkus.test.junit.main.QuarkusMainIntegrationTest;
@QuarkusMainIntegrationTest
public class HelloIT extends HelloTest {
}
```
### Limitations
`@QuarkusMainTest` does **not** support the following features:
- Injection of CDI beans
- Using Panache entities
- Using mocks with `@InjectMock`
Usually, it’s best to use a combination of `@QuarkusMainTest` tests for testing application externals, and `@QuarkusTest` tests for fine-grained testing which requires access to application internals.
#### Mocking
CDI injection is not supported in the `@QuarkusMainTest` tests. Consequently, mocking CDI beans with `QuarkusMock` or `@InjectMock` is not supported either.
It is possible to mock CDI beans by leveraging [test profiles](https://quarkus.io/guides/getting-started-testing#testing_different_profiles) though.
For instance, in the following test, the launched application would receive a mocked singleton `CdiBean1`. The implementation `MockedCdiBean1` is provided by the test:
```
package org.acme.commandmode.test;
import java.util.Set;
import jakarta.enterprise.inject.Alternative;
import jakarta.inject.Singleton;
import org.junit.jupiter.api.Test;
import org.acme.commandmode.test.MyCommandModeTest.MyTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainTest;
@QuarkusMainTest
@TestProfile(MyTestProfile.class)
public class MyCommandModeTest {
@Test
@Launch(value = {})
public void testLaunchCommand(LaunchResult result) {
// ... assertions ...
}
public static class MyTestProfile implements QuarkusTestProfile {
@Override
public Set<Class<?>> getEnabledAlternatives() {
return Set.of(MockedCdiBean1.class); (1)
}
}
@Alternative (2)
@Singleton (3)
public static class MockedCdiBean1 implements CdiBean1 {
@Override
public String myMethod() {
return "mocked value";
}
}
}
```
| | |
|---|---|
| **1** | List all the CDI beans for which you want to enable an alternative mocked bean. |
| **2** | Use `@Alternative` without a `@Priority`. Make sure you don’t use `@Mock`. |
| **3** | The scope of the mocked bean should be consistent with the original one. |
Using this pattern, you can enable specific alternatives for any given test. |
| Shard | 106 (laksa) |
| Root Hash | 3107096317879824306 |
| Unparsed URL | io,quarkus!/guides/command-mode-reference s443 |