Ruby Gotcha: Environment Variables Are Always Strings

Ruby environment variables are always strings. Learn why ENV['FLAG']='false' is still truthy and how to safely handle boolean environment variables in Rails applications.

I recently ran into a small but frustrating production bug caused by a common Ruby mistake.

I had a feature controlled by an environment variable:

DISABLE_THING=false

The application restarted successfully, but the feature was still disabled.

The reason? In Ruby, environment variables are always strings.

ENV["DISABLE_THING"]
# => "false"

And in Ruby, a non-empty string is truthy.

if "false"
  puts "This runs!"
end

# This runs!

So even though the value looks like false, Ruby sees it as a string containing five characters, not the boolean value false.


Ruby only has two falsey values

Ruby has a very simple truthiness rule:

  • false is falsey
  • nil is falsey
  • Everything else is truthy

That means:

!!"false"
# => true

!!"0"
# => true

!!""
# => true

The empty string is also truthy in Ruby.

This is different from some other programming languages where empty strings or values like "false" may be treated as false.


The common ENV mistake

A common pattern looks like this:

if ENV["ENABLE_FEATURE"]
  enable_feature
end

This works when the variable is missing:

ENV["ENABLE_FEATURE"]
# => nil

But it breaks when someone sets:

ENABLE_FEATURE=false

because Ruby receives:

ENV["ENABLE_FEATURE"]
# => "false"

and:

if "false"
  enable_feature
end

The feature gets enabled.


Convert ENV values into booleans

Before using environment variables as booleans, always cast them.

Option 1: ActiveSupport Boolean casting

If you are using Rails, ActiveSupport already provides a boolean type caster:

ActiveModel::Type::Boolean.new.cast(ENV["ENABLE_FEATURE"])

Examples:

ActiveModel::Type::Boolean.new.cast("true")
# => true

ActiveModel::Type::Boolean.new.cast("false")
# => false

ActiveModel::Type::Boolean.new.cast(nil)
# => nil

This is usually my preferred approach in Rails applications.


Option 2: Create a small helper

For smaller applications, a simple helper works well:

def env_truthy?(key)
  ENV[key].to_s.match?(/\A(true|t|1|yes|y|on)\z/i)
end

Usage:

if env_truthy?("ENABLE_FEATURE")
  enable_feature
end

Now:

ENABLE_FEATURE=true

enables the feature, while:

ENABLE_FEATURE=false

does not.


Prefer positive feature flags

Another small improvement is to avoid negative flags.

Instead of:

DISABLE_NEW_CHECKOUT=false

prefer:

ENABLE_NEW_CHECKOUT=true

Negative flags often create confusing conditions:

unless ENV["DISABLE_NEW_CHECKOUT"]
  enable_checkout
end

Positive flags are easier to reason about:

if env_truthy?("ENABLE_NEW_CHECKOUT")
  enable_checkout
end

A quick reference table

ENV value Ruby value Boolean result
"true" String truthy
"false" String truthy
"1" String truthy
"0" String truthy
"" String truthy
nil nil falsey

Takeaway

Environment variables are strings. Always.

Never assume this:

ENV["FLAG"] == false

or:

if ENV["FLAG"]

means what you think it means.

Convert the value first:

ActiveModel::Type::Boolean.new.cast(ENV["FLAG"])

or use a dedicated helper.

A five-second boolean conversion can save hours of debugging in production.

Saroj Maharjan

Senior Software Engineer building reliable Rails systems and practical AI products.

Berlin, Germany https://sarojmaharjan.com