Reason #142 • May 22nd, 2026

Interacting with environment variables via ENV

All programming languages provide some way to interact with environment variables, but I dare say that Ruby's ENV is the most elegant of them all.

Let's have a look at how we read and write environment variables in a few different languages, ordered by how much ceremony they require:

C
#include 
#include 

int main() {
  // Reading an environment variable
  char *value = getenv("MY_ENV_VAR");
  if (value) printf("Value: %s\n", value);

  // Writing an environment variable
  setenv("MY_ENV_VAR", "new_value", 1);

  return 0;
}
    
Java
public class EnvExample {
  public static void main(String[] args) {
    // Reading an environment variable
    String value = System.getenv("MY_ENV_VAR");
    if (value != null) System.out.println("Value: " + value);

    // Writing environment variables isn't directly supported
  }
}
    
Python
import os

# Reading an environment variable
value = os.getenv("MY_ENV_VAR")
print(f"Value: {value}")

# Writing an environment variable
os.environ["MY_ENV_VAR"] = "new_value"
    
JavaScript (Node.js)
// Reading an environment variable
const value = process.env.MY_ENV_VAR;
console.log(`Value: ${value}`);

// Writing an environment variable
process.env.MY_ENV_VAR = "new_value";
    
Perl
# Reading an environment variable
my $value = $ENV{"MY_ENV_VAR"};
print "Value: $value\n" if defined $value;

# Writing an environment variable
$ENV{"MY_ENV_VAR"} = "new_value";
    
Ruby
# Reading an environment variable
value = ENV["MY_ENV_VAR"]
puts "Value: #{value}"

# Writing an environment variable
ENV["MY_ENV_VAR"] = "new_value"
    

Perl gets pretty close, but the $ prefix is off-putting enough to make Ruby the clear winner

What's also nice about ENV is that it behaves mostly like a regular hash, even though it's actually a special object that interfaces with the operating system's environment variables. This means we can use all the familiar hash methods on it, like ENV.keys, ENV.values, ENV.each (together with all the Enumerable methods), etc.

Curiously, ENV.class is Object. That is to say, it doesn't have its own class. Presumably because it would be weird to create more than one instance of it.

History

ENV has been around since Ruby's inception.

Ruby 1.4 added to_hash.

Ruby 1.6 added conveniences like fetch and store.

Ruby 1.8 filled in more of the familiar mutating methods, such as clear, replace, and update.

Ruby 2.0 added to_h, and later versions added newer Hash methods such as slice, except, and filter.