Environment variables in Golang | LoginRadius Blog
Mục Lục
Before You Get Started
This tutorial assumes you have:
- A basic understanding of Go Language
- Latest Golang version installed on your system
- A few minutes of your time.
In this article, we will know about environment variables and why to use them. And will access them in a Go application using inbuilt and third-party packages.
What are environment variables?
Environment variables are key-value pair on a system-wide level, and running processes can access that. These are often used to make the same program behave differently in different deployment environments like PROD, DEV, or TEST.
Storing configuration in the environment is one of the principles of a twelve-factor app. It enables applications to be portable.
Why should you use environment variables
- If you are using the sensitive information in the code, then all the unauthorized users who have access to the code will have sensitive data, you might not want that.
- If you are using the code versioning tool like
git
, you may push your DB credentials with the code, and it will become public. - If you are managing variables in one place, in case of any changes, you don’t have to change it in all the places in application code.
- You can manage multiple deployment environments like PROD, DEV, or TEST. Environment variables are easy to change between deploys without changing any application code.
Never forget to include your environment variable files in the .gitignore
Inbuilt OS package
You don’t need any external package to access the environment variables in Golang, and you can do that with the standard os
package. Below is the list of functions related to environment variables and there uses.
os.Setenv()
sets the value of an environment value.os.Getenv()
gets the value environment variable named by the key.os.Unsetenv()
delete a single environment value named by the key, if we try to get that environment value usingos.Getenv()
it will return an empty value.os.ExpandEnv
replaces ${var} or $var in the string as per the values of environment variables. If any environment variable is not present an empty string will replace it.os.LookupEnv()
gets the value environment variable named by the key. If the variable is not present in the system, the returned value will be empty, and the boolean will be false. Otherwise, it returns the value (which can be empty), and the boolean is true.
os.Getenv() will return an empty string if the environment variable is not present, to distinguish between an empty value and an unset value, use LookupEnv.
Now let’s use all the above functions in our code. Create a main.go file in an empty folder.
package
main
import
(
"fmt"
"os"
)
func
main
() {
// Set Environment Variables
os.
Setenv
(
"SITE_TITLE"
,
"Test Site"
)
os.
Setenv
(
"DB_HOST"
,
"localhost"
)
os.
Setenv
(
"DB_PORT"
,
"27017"
)
os.
Setenv
(
"DB_USERNAME"
,
"admin"
)
os.
Setenv
(
"DB_PASSWORD"
,
"password"
)
os.
Setenv
(
"DB_NAME"
,
"testdb"
)
// Get the value of an Environment Variable
host
:= os.
Getenv
(
"SITE_TITLE"
)
port
:= os.
Getenv
(
"DB_HOST"
)
fmt.
Printf
(
"Site Title: %s, Host: %s
\n
"
, host, port)
// Unset an Environment Variable
os.
Unsetenv
(
"SITE_TITLE"
)
fmt.
Printf
(
"After unset, Site Title: %s
\n
"
, os.
Getenv
(
"SITE_TITLE"
))
//Checking that an environment variable is present or not.
redisHost
,
ok
:= os.
LookupEnv
(
"REDIS_HOST"
)
if
!ok {
fmt.
Println
(
"REDIS_HOST is not present"
)
}
else
{
fmt.
Printf
(
"Redis Host: %s
\n
"
, redisHost)
}
// Expand a string containing environment variables in the form of $var or ${var}
dbURL
:= os.
ExpandEnv
(
"mongodb://${DB_USERNAME}:${DB_PASSWORD}@$DB_HOST:$DB_PORT/$DB_NAME"
)
fmt.
Println
(
"DB URL: "
, dbURL)
}
Below is the output when we run go run main.go
in our terminal
go
run main.
go
//output
Site Title: Test Site, Host: localhost
After unset, Site Title:
27017
REDIS_HOST is not present
DB URL: mongodb:
//admin:password@localhost:27017/testdb
There are two more functions os.Clearenv
and os.Environ()
let’s use them also in a separate program.
os.Clearenv
deletes all environment variables, It can be useful to clean up the environment for testsos.Environ()
returns a slice of the string containing all the environment variables in the form of key=value.
package
main
import
(
"fmt"
"os"
"strings"
)
func
main
() {
// Environ returns a slice of string containing all the environment variables in the form of key=value.
for
_
,
env
:=
range
os.
Environ
() {
// env is
envPair
:= strings.
SplitN
(env,
"="
,
2
)
key
:= envPair[
0
]
value
:= envPair[
1
]
fmt.
Printf
(
"%s : %s
\n
"
, key, value)
}
// Delete all environment variables
os.
Clearenv
()
fmt.
Println
(
"Number of environment variables: "
,
len
(os.
Environ
()))
}
The above function will list all the environment variables available in the system, including NAME
and DB_HOST
. Once we run os.Clearenv()
it will clear all the environment variables for the running process.
godotenv package
The Ruby dotenv project inspires GoDotEnv package, it loads the environment variables from a .env file
Let’s create a .env file in which we will have all our configurations.
# .env file
# This is a sample config file
SITE_TITLE
=Test Site
DB_HOST
=localhost
DB_PORT
=
27017
DB_USERNAME
=admin
DB_PASSWORD
=password
DB_NAME
=testdb
Then in the main.go file we will use godotenv to load the environment variables.
we can load multiple env files at once also. godotenv also supports YAML.
// main.go
package
main
import
(
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func
main
() {
// load .env file from given path
// we keep it empty it will load .env from current directory
err
:= godotenv.
Load
(
".env"
)
if
err !=
nil
{
log.
Fatalf
(
"Error loading .env file"
)
}
// getting env variables SITE_TITLE and DB_HOST
siteTitle
:= os.
Getenv
(
"SITE_TITLE"
)
dbHost
:= os.
Getenv
(
"DB_HOST"
)
fmt.
Printf
(
"godotenv : %s = %s
\n
"
,
"Site Title"
, siteTitle)
fmt.
Printf
(
"godotenv : %s = %s
\n
"
,
"DB Host"
, dbHost)
}
Open the terminal and run the main.go
go
run main.
go
// output
godotenv : Site
Title
= Test Site
godotenv : DB
Host
= localhost
Viper package
Viper is a complete configuration solution for Go applications including twelve-factor apps. It is designed to work within an application and can handle all types of configuration needs and formats.
Viper supports many file formats to load environment variables, e.g., Reading from JSON, TOML, YAML, HCL, envfile and Java properties config files. So in this example, we will look at how to load environment variables from a YAML file.
YAML is a human-readable data-serialization language. It is commonly used for configuration files and in applications where data is being stored or transmitted.
Let’s create our config.yaml and main.go in an empty folder.
# config.yaml
SITE
:
TITLE
:
Test Site
DB
:
HOST
:
"localhost"
PORT
:
"27017"
USERNAME
:
"admin"
PASWORD
:
"password"
NAME
:
"testdb"
In the below code, we are using Viper to load environment variables from a config.yaml. We can load the config file from any path we want. We can also set the default values for any environment variable if any environment variable is not available in the config file.
// main.go
package
main
import
(
"fmt"
"log"
"os"
"github.com/spf13/viper"
)
func
main
() {
// Set the file name of the configurations file
viper.
SetConfigName
(
"config"
)
// Set the path to look for the configurations file
viper.
AddConfigPath
(
"."
)
// Enable VIPER to read Environment Variables
viper.
AutomaticEnv
()
viper.
SetConfigType
(
"yml"
)
if
err
:= viper.
ReadInConfig
(); err !=
nil
{
fmt.
Printf
(
"Error reading config file, %s"
, err)
}
// Set undefined variables
viper.
SetDefault
(
"DB.HOST"
,
"127.0.0.1"
)
// getting env variables DB.PORT
// viper.Get() returns an empty interface{}
// so we have to do the type assertion, to get the value
DBPort
,
ok
:= viper.
Get
(
"DB.PORT"
).(
string
)
// if type assert is not valid it will throw an error
if
!ok {
log.
Fatalf
(
"Invalid type assertion"
)
}
fmt.
Printf
(
"viper : %s = %s
\n
"
,
"Database Port"
, DBPort)
}
Open the terminal and run the main.go
go
run main.
go
// output
viper : Database
Port
=
27017
Conclusion
Using environment variables is an excellent way to handle configuration in our application. Overall, it provides you with easy configuration, better security, multiple deployment environments and fewer production mistakes.
Now you can manage environment variables in your go application, and You can found the complete code used in this tutorial on our Github Repo