Java Feature Flags & Toggles: A Step-by-Step Guide with a Working Java Application

Introduction to Java Feature Flags
In this tutorial, we will learn how to use the Flagsmith Java SDK for a Java application. We will cover the fundamentals of feature flags/toggles, how to build a basic Java server application, and how to integrate Flagsmith's Java feature flags SDK to make the application much more powerful. This is a zero pre-requisite guide.
So, let's dive deeper into the Java feature toggle topic!
What is a feature flag?
Before we dive into the development work, let’s first understand what feature flags or feature toggles are, and how they can help development teams deliver value more quickly.
Feature flags are one of the most important components of any application. They let you modify the functionality of your code without the need for any code merge, redeployment, or any other heavy lifting. Toggling a feature flag is (in general) becomes as simple as clicking a UI button. Feature flags have the power to make releases a lot more efficient and a lot lower risk, as rollouts (and roll backs) become much easier.
Feature flags let you to turn some behaviour of code on/off, or they let you alter the code behaviour based on the feature flag value. As a basic feature flag example, say you frequently want to change the price of an article on your website without needing to redeploy code—you could do this with a feature flag in Java. There are various ways feature flagging can be implemented here: a) fetch the value periodically from the server, b) fetch the value every time it is required. We will be looking at both of these methods in detail below.
What are some use cases for Java feature flags?
Java feature flags can help with more efficient feature rollouts to customers and are often a part of making deployment processes more agile. They can be used for things like phased rollouts and gradual feature rollouts, A/B testing, segmentation and releasing to different user groups, behaviour experiments, and feature versioning. (Plus, wrapping the code in a flag helps with easier rollbacks if anything does go wrong.)
Why use feature flags in Java?
Let’s understand this through a very simple real life example:
Imagine you are driving a car and suddenly the air conditioner in your car starts making a weird noise. I’m sure as a first thing you would try to change the fan speed / modes of the air conditioner and that doesn’t help, you will turn it off. Next, you will reach out to a mechanic and once the part is fixed, you will turn the AC back on and continue with your journey.
This is analogous to how you would use feature flags when anything goes wrong with your application. The fan speed / modes that we talked about above are the feature flag values that can be updated. Turning it off is the same as disabling the feature flag. This would prevent your app clients from viewing a weird or unexpected error screen on that particular page. Ideally when the feature flag is disabled, you would show users a message like, “This page is under maintenance. Please come back later!”. Once the issue is fixed, you can re-enable the feature flag.
To get the most out of flags, there are feature toggle best practices you can follow.
Why Flagsmith?
Flagsmith provides a (free) all-in-one platform for developing, implementing, and managing your feature flags. It offers you the capability to leverage feature flags to their maximum potential by storing values inside them. These values can be used to toggle multiple kinds of behaviours as illustrated in the “What are Feature Flags” section.
Flagsmith is an open-source tool which makes it very trustworthy.
Flagsmith provides seamless integration with well maintained documents for multiple programming languages across web, mobile, and server-side applications. It offers various customisations which makes it very convenient to use. It has a very simple UI which allows you to alter your code behaviour without needing to focus on feature flag internal implementation at all.
Let’s get started with Java Feature Toggles!
As a first step, we need to create an account on https://flagsmith.com/. It offers simple sign in with Google or Github options. Or you can just fill your basic details on https://app.flagsmith.com/signup. The below screenshot shows the signup process:

It will then ask you to create an organisation. For the purpose of this tutorial I’ll name it Java Feature Flag WebServer Tutorial. You can name it anything you like.

Next, we need to create a project inside this organisation
Click on “Create A Project”. The below screen should pop up. Enter your project name. I’m creating a project with the name “My GoLang Server”. Feel free to name it whatever you’d like.

Congrats! You have already completed the Flagsmith set up process. You should see the below screen now.

We will come back to this screen when we want to add a feature flag to our application.
Now, let’s start by creating a Java WebServer application.
Let’s code!
To keep this tutorial simple, we will create a rudimentary Java server application. It will be exposed on localhost and will use the local system storage. This server maintains a list of books and exposes two APIs:
- to add a new book and
- to query the books present in its records.
If you do not have Java installed on your system, download and install the latest stable version from this link based on your OS and System specifications.
TL;DR: All the code is present at https://github.com/abhishekag03/flagsmith-java-feature-flag-demo.git with step by step commits. Feel free to refer to it at any time if you feel confused.
Step 1: Java set up
Make sure you have Java installed by running this command on your terminal:
java -version
I’m on version 1.19.1, thus getting the below output.

Step 2: Create a blank Maven / Gradle project
Most modern IDEs offer the functionality to create a Maven or Gradle project with just a few clicks of buttons. Here, I will be creating a Maven project on IntelliJ.
I have kept the project specifications as shown below:

The image below shows the base directory structure that got auto-created. The Main.java file below has a basic “Hello world” function.

Step 3: Use the HttpServer library to create a basic HTTP server
Refer this PR for quick reference
We will expose port 8000 and expose a single endpoint. Below code exposes localhost:8000/test, and just returns “This is the response” with a Status code 200.
package org.flagsmith;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
public class Main {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/test", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
String response = "This is the response";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
Run your application by clicking the green “Run” button on your IDE.
The same can be verified by hitting the test endpoint via curl from your terminal.
curl localhost:8000/test
Output should be as shown below

Step 4: Add GET and POST handlers
Modify the handle function so that it can call the appropriate method based on Request type. We are using a common endpoint for GET and POST requests. The implementation to both of these methods will be added in the steps that follow.
@Override
public void handle(HttpExchange t) throws IOException {
if ("GET".equals(t.getRequestMethod())) {
handleGetBooksRequest(t);
} else if ("POST".equals(t.getRequestMethod())) {
handlePostBooksRequest(t);
}
}
private void handleGetBooksRequest(HttpExchange t) throws IOException {
}
private void handlePostBooksRequest(HttpExchange t) throws IOException {
}
Step 5: Create a Book class to structure the data
Here I’m creating a Book class with 4 attributes -
- id
- title
- author
- price.
This class should be in the same directory as your main.java file.
Also, adding getters, setters and a constructor for the same.
package org.flagsmith;
public class Book {
String id;
String title;
String author;
String price;
public Book(String id, String title, String author, String price) {
this.id = id;
this.title = title;
this.author = author;
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Step 6: Populate dummy data
First, we need to populate some dummy data containing books. We will have a global books variable to store the new and existing books. Initilialise this in the Main class.
static List<Book> books = new ArrayList<>();
Populate this books list with 3 same books using the below function:
private static void populateDummyData() {
books.add(new Book("1", "Harry Potter", "J.K. Rowling", "20.99"));
books.add(new Book("2", "War and Peace", "Leo Tolstoy", "26.99"));
books.add(new Book("3", "The Kite Runner", "Khaled Hosseini", "30.99"));
}
Your main method should now look as follows:
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/books", new MyHandler());
server.setExecutor(null); // creates a default executor
populateDummyData();
server.start();
}
Note that the endpoint name has been updated to `books` now.
Step 7: Complete the GET endpoint
We need to add the gson library to our pom.xml dependencies since it makes string <-> json conversion much easier. Add the below lines to pom.xml file:
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
Update the handleGetBooksRequest implementation to return the books list that we populated above with 200 Response code.
Add this import to the Main.java file:
import com.google.gson.Gson;
private void handleGetBooksRequest(HttpExchange t) throws IOException {
OutputStream os = t.getResponseBody();
String json = new Gson().toJson(books);
t.sendResponseHeaders(200, json.length());
os.write(json.getBytes());
os.close();
}
Run the application and test it from your terminal:
curl localhost:8000/books
This image shows the expected output. You should be able to see all the books we populated above.

Step 7: Complete the POST endpoint
From our POST endpoint, we should be able to add new books to our existing collection. We will allow adding one book at a time only.
The following imports will also be required:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
Handling the POST request can be done with the following code. We will print a message saying “book added successfully”, once the book has been added.
private void handlePostBooksRequest(HttpExchange t) throws IOException {
Book book = getBookFromRequest(t);
books.add(book);
OutputStream os = t.getResponseBody();
String resp = "book added successfully";
t.sendResponseHeaders(200, resp.length());
os.write(resp.getBytes());
os.close();
}
We need a utility function to parse the request and extract a `book` object from the same. Below function helps us do the same:
private static Book getBookFromRequest(HttpExchange t) throws IOException {
InputStreamReader isr = new InputStreamReader(t.getRequestBody(), StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr);
String query = br.readLine();
Gson gson = new Gson();
return gson.fromJson(query, Book.class);
}
Run the application and try out the below POST request to add a book titled “Famous Five”:
curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 20}"
The Terminal must show “book added successfully”

Since this book is now added to the global storage, hitting the GET endpoint now should return 4 books in total.
curl localhost:8000/books

Step 8: Add the power of Flagsmith Java Feature Flag Software
With flagsmith, we can control a variety of components of our Web Server. Let’s imagine a case where we do not want to allow adding new books for a certain interval of time. The naive way is to edit the code and put a logic there to stop adding new books and then remove this logic once we want to allow it back.
What if this could be done with the click of a button? Flagsmith allows us to do that with a very minimal one time configuration. We will create a new feature that will stop allowing users to add new books when turned off.
Time to return to our Flagsmith UI. Click on the “Create Feature” button on the screen we left off above.
Add a new feature flag by the name “add_books”. This will control whether or not we allow adding new books. Turn `Enabled by default` to “true”. Below screenshot shows the configuration.

Value can be left blank, we will come back to it later. Click on “Create Feature” (Make sure you have enabled it). The UI should show the following:

We will also need a Flagsmith Server-side environment key to initialise the feature flag client. Let’s generate that.
Navigate to “SDK Keys” from the left bar on the Flagsmith page. Click on “Create Server-Side Environment Key”. Give it a name for e.g: “java-demo”

Keep the key handy in your notes. It should be of the form “ser.******....”
Step 9: Integrate Flagsmith with your application
Refer to this Pull Request for quick reference
Flagsmith provides a Java SDK, which is very easy to integrate. We just need to add the below dependency to our pom.xml file and recompile the dependencies.
<dependency>
<groupId>com.flagsmith</groupId>
<artifactId>flagsmith-java-client</artifactId>
<version>7.4.3</version>
</dependency>
OR if you have a gradle project:
implementation 'com.flagsmith:flagsmith-java-client:7.4.3'
Add this import to the `Main.java` file
import com.flagsmith.FlagsmithClient;
We first need to add the API key that we copied above to a properties file in our source code. Create a new file by the name `config.properties` in the `resources` directory.
The `config.properties` file should have one property:
apiKey=ser.********
The below utility function will help us extract the API key from the properties file. This can be added to the Main class. In an ideal scenario, these helper methods must reside in a utility class such as `FeatureFlagService.java`.
import java.util.Properties;
import java.io.*;
private static String readFlagsmithApiKey() {
Properties prop = new Properties();
String propFileName = "config.properties"; // if this does not work, use propFileName = "resources/config.properties"
InputStream inputStream = ClassLoader.getSystemResourceAsStream(propFileName);
if (inputStream != null) {
try {
prop.load(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException("config file input stream is null");
}
return prop.getProperty("apiKey");
}
This function will be used to initialise the Flagsmith client.
private static FlagsmithClient getFlagsmithClient() {
String apiKey = readFlagsmithApiKey();
return FlagsmithClient
.newBuilder()
.setApiKey(apiKey)
.build();
}
Create a global Flagsmith client variable that can be used by all the handlers. This client must be initialised before starting the server.
public class Main {
static List<Book> books = new ArrayList<>();
static FlagsmithClient fsClient;
// rest of the code follows
Initialise the `fsClient` inside the `main` function:
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
populateDummyData();
fsClient = getFlagsmithClient();
server.createContext("/books", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
Step 10: Use the Java feature toggle to control API behaviour
Refer to this Pull Request for quick reference
We will now modify our POST request handler so that it allows adding new books only when the feature flag is enabled. The modified handlePostRequest method looks as follows:
private void handlePostBooksRequest(HttpExchange t) throws IOException {
boolean allowAddBooks;
try {
Flags flags = fsClient.getEnvironmentFlags(); // get all environment flags
allowAddBooks = flags.isFeatureEnabled("add_books"); // check value of add_books env flag
} catch (FlagsmithClientError e) {
throw new RuntimeException(e);
}
String resp;
int respCode;
if (allowAddBooks) { // allow adding books only if feature flag returns True
Book book = getBookFromRequest(t); // parse book data from request
books.add(book);
resp = "book added successfully";
respCode = 201;
} else {
resp = "method not allowed. Please come back later";
respCode = 405;
}
OutputStream os = t.getResponseBody();
t.sendResponseHeaders(respCode, resp.length());
os.write(resp.getBytes());
os.close();
}
Above code will require adding the below two imports as well:
import com.flagsmith.exceptions.FlagsmithClientError;
import com.flagsmith.models.Flags;
By default the feature flag is on and hence we should be able to add a new book.
Run the application and try adding a new book with the below request.
curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 20}"
You should be able to see a success message. This book gets added successfully.

Now, we will try turning the `add_books` feature off. Navigate to the Flagsmith UI and toggle it “off” as shown below.

Trying the same POST request as above now gives an error message saying “method not allowed. Please come back later”.

This is how powerful Flagsmith is. With just one click, we could change the functionality of our application entirely. No re-deployment or code change required.
Step 11: Leveraging Java feature toggle values
Refer to this Pull Request for quick reference
While creating a new feature, we saw an option to add a feature value. Let’s understand how that can be useful.
For instance, due to some requirement we only want to accept books that have a price greater than $20. This is to avoid filling up our library with cheap and less selling books. Also, helps us maintain a standard.
However, we want to keep varying this threshold price based on the rush and staff capacity. It is definitely not feasible to amend the code every time as per the requirement.
What if this can also be achieved with the click of a button? Yes, with Flagsmith it can be.
Go ahead and update the feature flag value to 20 as shown in the below image. Also, do enable the feature back so that we can continue testing.

We need to update our code slightly to also read the feature flag value and act accordingly.
private void handlePostBooksRequest(HttpExchange t) throws IOException {
boolean allowAddBooks;
int minPrice;
try {
Flags flags = fsClient.getEnvironmentFlags(); // get all environment flags
allowAddBooks = flags.isFeatureEnabled(ADD_BOOKS_FEATURE_FLAG); // check value of add_books env flag
minPrice = (int) flags.getFeatureValue(ADD_BOOKS_FEATURE_FLAG); // get minimum price of book that can be added
} catch (FlagsmithClientError e) {
throw new RuntimeException(e);
}
String resp;
int respCode;
if (allowAddBooks) { // allow adding books only if feature flag returns True
Book book = getBookFromRequest(t); // parse book data from request
if (Integer.parseInt(book.price) >= minPrice) {
books.add(book);
resp = "book added successfully";
respCode = 201;
} else {
resp = "book value less than minimum price allowed";
respCode = 406;
}
} else {
.....
// rest code remains as it is
Note the following things:
- The if condition inside `allowAddBooks` checks if the book price meets our minimum price condition. If it does, it would add it to the books list, else return an error message.
- The “add_books” feature flag string has been replaced with a constant “ADD_BOOKS_FEATURE_FLAG” which has the value “add_books”
Testing the above change:
Make sure to re-run the application after the code changes are complete.
1. Adding a book with price $25 (should work):

2. Adding a book with price $15 (should throw an error):
curl -X POST -H "Content-type:application/json" "http://localhost:8000/books" -d "{\"id\": \"4\",\"title\": \"Famous Five\",\"author\": \"Enid Blyton\",\"price\": 15}"

Both the results are as expected. The first one worked successfully and the second one threw an error.
Step 12: Flagsmith Local Evaluation mode
Refer to this Pull Request for quick reference
We just saw above that every time a POST request is made to our server, it will make an additional API call to fetch the feature flag value. This sounds like an expensive operation, especially in the case when our server receives thousands or millions of requests per minute.
In such cases, the Local evaluation mode is the best suited. With this, the feature flag value gets auto fetched periodically after a defined interval (say 1 minute). Thus, it would not make a call every time to the Flagsmith server. This saves us a lot of time per request in large scale systems.
A thing to keep in mind is that this does not allow sudden change in behaviour of our application. Hence, this should not be used in the case when we are dealing with financial data or some millisecond sensitive updates. The change will take up to X seconds to reflect in your code, where X is the refresh time interval you set while initialising the client.
Let’s look at an example with the Local Evaluation mode client which refreshes every 1 minute. We need to modify the `getFlagsmithClient` function with config as shown below:
private static FlagsmithClient getFlagsmithClient() {
String apiKey = readFlagsmithApiKey();
FlagsmithConfig flagsmithConfig = FlagsmithConfig
.newBuilder()
.withLocalEvaluation(true)
.withEnvironmentRefreshIntervalSeconds(60)
.build();
return FlagsmithClient
.newBuilder()
.setApiKey(apiKey)
.withConfiguration(flagsmithConfig)
.build();
}
Add this corresponding import:
import com.flagsmith.config.FlagsmithConfig;
Let’s create a basic python script that will help us fire 50 POST requests in succession. This will help us compare the performance.
import requests
import time
data = {
'id': '4',
'title': 'Test book',
'author': 'Betty Carter',
'price': 49.99,
}
start = time.time()
for i in range(50):
x = requests.post('http://localhost:8000/books', json=data)
end = time.time()
print("Total time taken: ", end - start)
Save the above script and run it in two cases:
- Without local evaluation config applied

- With local evaluation config applied

Notice the difference in time. It’s 6.24 seconds v/s 0.25 seconds
This is a huge difference. This is just an example of how much time the local evaluation mode saves in our application. In servers getting loads of requests, this will be especially very helpful.
Conclusion
In this step-by-step guide, we walked through using flags in your Java applications. Feature flags in Java can give you a lot of control and agility in your software development process, lowering the risk of releases (thanks to things like easier rollbacks). This lets you release features with confidence, experiment with new functionalities, and roll out features in a more targeted way based on analytics and customer segmentation.
Get Started
If you like this Java feature flag guide, check out our SDK list (including the Java SDK). Or get started with a free account to try feature flagging.
Why Flagsmith?
- It’s free to start - so you can leverage and try feature flags right away
- Flagsmith is open-source - which makes it very trustworthy. You can look through the code, check out the roadmap, and create issues if you notice anything. Transparency is one of the biggest benefits of choosing open-source feature flags.
- Flexible deployment options and the ability to deploy on-premises. Keep control of your flags and infrastructure.
- Flagsmith offers integrations with CI/CD tools, A/B testing and analytics tools, and more. It fits within your current workflows and tech stack so you don't need to add another decision point.
More Reading
If you like this Java feature flags guide, check out our documentation or read some of our other language/framework guides:
.webp)