Working with Java Environment Variables & 4 Ways to Set Variables

Java Environment Variables Blog Banner

What Are Environment Variables in Java? 

Environment variables in Java are external settings that influence system behaviors and configurations. They are useful for segregating environment-specific details from application code. These variables serve as parameters passed to the Java runtime environment, affecting its behavior or configurations without modifying the code. 

Operating systems like Windows, Linux, and macOS support these variables, allowing Java programs to adapt to different environments.

Environment variables are often used for managing project settings such as database configurations, API keys, and service endpoints. They avoid hardcoding sensitive data directly into the source code, increasing security and flexibility. This makes it easier to update settings without redeploying or altering the application’s codebase.

Use Cases for Environment Variables in Java 

There are several ways you can use environment variables in Java.

Storing API Keys

Environment variables are useful for securely storing sensitive information such as API keys. By keeping these keys out of the source code, developers ensure the security of their applications. Instead of hardcoding an API key directly in the code, it can be stored in an environment variable like API_KEY

In a Java application, you can access this key with:

String apiKey = System.getenv("API_KEY");

This approach ensures the API key is not embedded in the source code and not exposed in version control systems. Additionally, it allows easy updates to the key without modifying the codebase, making it possible to use different keys in different environments.

Defining Program Arguments

Environment variables can define program arguments, allowing applications to adapt their behavior based on the execution context. For example, a variable like ENV_MODE can indicate whether the application is running in development, testing, staging, or production mode:

String envMode = System.getenv("ENV_MODE");

In development mode, the application might enable verbose logging and debugging tools. In production, these features are typically disabled to enhance performance and security. This helps manage different configurations and behaviors dynamically, improving maintainability.

Setting Path Variables

Environment variables are also useful for setting path variables such as LOG_PATH or CONFIG_DIR. These variables specify directory paths for logging, configuration files, or other critical purposes. This flexibility allows applications to adapt to different environments without modifying the code:

String logPath = System.getenv("LOG_PATH");

For example, in a Java application, reading a configuration path from an environment variable allows it to adapt quickly to different file system layouts across development and production servers or different operating systems. This approach is particularly beneficial for applications that need to run on multiple platforms, where directory structures can vary.

Tips From the Expert

In my experience, here are tips that can help you better manage environment variables in Java:

  1. Use external configuration tools for sensitive data
    For production, avoid storing sensitive values like API keys in environment variables. Use external configuration management tools like HashiCorp Vault or AWS Secrets Manager to securely store and inject these secrets at runtime, enhancing security.

  2. Utilize Java system properties as an alternative
    When environment variables are not an option, use Java system properties (-Dproperty=value) to pass configuration values. This allows more flexibility in setting and overriding properties at runtime, especially in complex environments.

  3. Create fallback mechanisms for missing variables
    Always implement fallbacks for missing environment variables by providing defaults or throwing descriptive exceptions. This ensures your Java application behaves predictably in different environments and avoids runtime failures due to misconfigured environments.

  4. Use dependency injection frameworks
    Combine frameworks like Spring or Micronaut with environment variables to inject configuration values automatically. This simplifies your code by abstracting away direct calls to System.getenv(), promoting cleaner and more maintainable configurations.

  5. Avoid environment variable mutation at runtime
    Environment variables should be treated as immutable during application runtime. Changing them dynamically can cause inconsistent behavior, especially when other parts of the system are already using those variables. Stick to setting variables at startup.

Ran Cohen photo
Ran Cohen
CTO & Co-Founder. Configu
Before co-founding Configu, Ran was a full stack developer at Testim.io and previously served in an elite cybersecurity unit in the Israeli Defense Forces.

Accessing Environment Variables in Java 

You can access environment variables in Java using the System class provided by the standard Java library. Use the System.getenv(String name) method to retrieve the value of a specific environment variable. 

Accessing an environment variable

For example, to access an environment variable named API_KEY, you would use:

String apiKey = System.getenv("API_KEY");

Handling missing values

It’s a good practice to check if the environment variable is null (i.e., not set) to avoid a potential NullPointerException. For example:

String apiKey = Optional.ofNullable(System.getenv("API_KEY")).orElse("defaultValue");

Alternatively, you can throw an exception if the environment variable is missing:

Optional.ofNullable(System.getenv("API_KEY"))
        .orElseThrow(() -> new IllegalStateException("API_KEY environment variable is not defined"));

Obtaining a map of all environment variables

To get a Map<String, String> of all environment variables, use System.getenv(). This is useful if you want to iterate over all available environment variables. For example:

Map envVars = System.getenv();
for (String envName : envVars.keySet()) {
    System.out.format("%s=%s%n", envName, envVars.get(envName));
}

Alternatively, this can be written in one line:

System.getenv().forEach((k, v) -> System.out.println(k + "=" + v));

Setting Environment Variables in Java 

There are several ways to set environment variables in Java.

1. Using JUnit Pioneer Library

JUnit Pioneer is an extension pack for JUnit, a popular open source Java test framework. You can use JUnit Pioneer to easily set environment variables:

import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.SetEnvironmentVariable;

@Test
@SetEnvironmentVariable(key = "MY_ENV_VARIABLE", value = "MY_ENV_VARIABLE_VALUE")
void givenVariableSet_whenGetEnvironmentVariable_thenReturnsCorrectValue() {
    String actual = System.getenv("MY_ENV_VARIABLE");
    assertThat(actual).isEqualTo("MY_ENV_VARIABLE_VALUE");
}

This method uses the @SetEnvironmentVariable annotation to set the environment variable for the test method, making it easier to manage environment variables during testing.

2. Using JNI

Another method is to use the Java Native Interface (JNI) to set environment variables. This involves writing native code in C or C++ to interact with the operating system’s environment. Note that this approach has limitations such as platform dependencies and potential issues with Java runtime caching environment variables.

Here’s a basic example:

#include 
#include 

JNIEXPORT void JNICALL Java_SetEnv_setEnv(JNIEnv *env, jobject obj, jstring key, jstring value) {
    const char *nativeKey = (*env)->GetStringUTFChars(env, key, 0);
    const char *nativeValue = (*env)->GetStringUTFChars(env, value, 0);

    setenv(nativeKey, nativeValue, 1);

    (*env)->ReleaseStringUTFChars(env, key, nativeKey);
    (*env)->ReleaseStringUTFChars(env, value, nativeValue);
}

This JNI function sets an environment variable using the setenv function from the C standard library. 

The full process of setting environment variables with JNI is complex and outside our scope—it involves multiple steps including creating the Java class file, generating the header file, compiling C code into a shared library, and executing the Java main file.

3. Setting Variables for a Child Process

Using the ProcessBuilder class in Java, you can set environment variables for a child process. Here’s how you can do it:

import java.io.IOException;
import java.util.Map;

public class ChildProcessExample {
    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        Map environment = processBuilder.environment();
        environment.put("MY_ENV_VARIABLE", "MY_ENV_VARIABLE_VALUE");

        Process process = processBuilder.command("my-command").start();
        int exitCode = process.waitFor();
        System.out.println("Exit code: " + exitCode);
    }
}

This example sets an environment variable for the child process started by ProcessBuilder. It’s useful for scenarios where you need the environment variable to be available only within a specific subprocess.

4. Using Docker 

Docker is another useful way to manage environment variables for Java applications, especially for integration tests. You can define environment variables in the Dockerfile as follows. This Docker file is based on amazoncorretto, a free image created by Amazon that includes the Java Development Kit (JDK).

FROM maven:3.9.8-amazoncorretto-8-al2023
WORKDIR /app
COPY . /app
ENV MY_DOCKER_ENV_VARIABLE=TRUE
ENTRYPOINT ["mvn", "test"]

In your Java code, you can use libraries like Testcontainers to run tests inside a Docker container:

import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;

class DockerEnvironmentTest {
    @Test
    void givenDockerEnvironment_whenGetEnvironmentVariable_thenReturnsCorrectValue() {
        try (GenericContainer container = new GenericContainer<>("my-docker-image")
                .withEnv("MY_ENV_VARIABLE", "MY_ENV_VARIABLE_VALUE")) {
            container.start();
            // My custom tests
        }
    }
}

This approach ensures that your environment variables are isolated within the container, providing a controlled environment for testing and deployment.

Related content: Read our guide to testing environment

Managing Java Environment Variables with Configu

Configu is a configuration management platform comprised of two main components, the stand-alone Orchestrator, which is open source, and the Cloud, which is a SaaS solution:

Configu Orchestrator

As applications become more dynamic and distributed in microservices architectures, configurations are getting more fragmented. They are saved as raw text that is spread across multiple stores, databases, files, git repositories, and third-party tools (a typical company will have five to ten different stores).

The Configu Orchestrator, which is open-source software, is a powerful standalone tool designed to address this challenge by providing confConfigu is a configuration management platform comprised of two main components, the stand-alone Orchestrator, which is open source, and the Cloud, which is a SaaS solution:

Configu Cloud

Configu Cloud is the most innovative store purpose-built for configurations, including environment variables, secrets, and feature flags. It is built based on the Configu configuration-as-code (CaC) approach and can model configurations and wrap them with unique layers, providing collaboration capabilities, visibility into configuration workflows, and security and compliance standardization.

Unlike legacy tools, which treat configurations as unstructured data or key-value pairs, Configu is leading the way with a Configuration-as-Code approach. By modeling configurations, they are treated as first-class citizens in the developers’ code. This makes our solution more robust and reliable and also enables Configu to provide more capabilities, such as visualization, a testing framework, and security abilities.

Learn more about Configu

Related Content

Setting Environment Variables in PowerShell: A Practical Guide

React Environment Variables: Basics, Tutorial, and Best Practices

Working with Python Configuration Files: Tutorial & Best Practices

Jenkins Environment Variables: Practical Guide with Code Examples

7 Types of Testing Environments and Best Practices for Yours

4 Ways to Set Docker Compose Environment Variables

How to Use Github Actions Environment Variables

Next.js Environment Variables: Built-In, Public, and Private

Node.js Environment Variables: Working with process.env and dotenv

Environment Variables: How to Use Them and 4 Critical Best Practices

Setting Docker Environment Variables: The Ultimate Guide

Leveraging Environment Variables in Python Programming

Try Configu for free
Painless end-to-end configuration management platform
Get Started for Free