<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Yannick Seeger</title><description>Notes on building software and running a business.</description><link>https://yseeger.me/</link><language>en</language><item><title>Typesafe Golang Configuration</title><link>https://yseeger.me/blog/typesafe-golang-configuration/</link><guid isPermaLink="true">https://yseeger.me/blog/typesafe-golang-configuration/</guid><description>How to configure your Go applications typesafe with environment variables.</description><pubDate>Wed, 11 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a developer, I&apos;ve experimented with various configuration formats over the years, including JSON, YAML, and properties files, among others. However, in recent times, I find myself increasingly relying on &lt;strong&gt;environment variables&lt;/strong&gt; to manage configuration values.&lt;/p&gt;
&lt;p&gt;In today&apos;s cloud-centric world, where stateless services are the norm, environment variables are an excellent fit, especially when working with containerization technologies like Docker or Kubernetes.&lt;/p&gt;
&lt;p&gt;To simplify the code for loading configurations and ensure type safety, I use two Go packages, namely &lt;a href=&quot;https://github.com/joho/godotenv&quot;&gt;godotenv&lt;/a&gt; and &lt;a href=&quot;https://github.com/kelseyhightower/envconfig&quot;&gt;envconfig&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;godotenv is a package that loads .env files if they exist. This is useful in local development environments, where you may not want to store sensitive configuration data in code.&lt;/li&gt;
&lt;li&gt;envconfig, on the other hand, &quot;loads&quot; existing environment variables into a struct. It supports the use of struct tags to specify alternate, default, and required environment variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;.env&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SERVICE_DEBUG=true
SERVICE_POSTGRES_DSN=postgresql://user@localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;config.go&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
  &quot;log&quot;
  &quot;github.com/joho/godotenv&quot;
  &quot;github.com/kelseyhightower/envconfig&quot;
)

type Config struct {
  Debug       bool    `default:&quot;false&quot;`
  PostgresDSN string  `envconfig:&quot;POSTGRES_DSN&quot;`
  Port        string  `default:&quot;:3000&quot;`
}

func LoadConfig() *Config {
  _ = godotenv.Load()
  var cfg Config
  err := envconfig.Process(&quot;SERVICE&quot;, &amp;amp;cfg)
  if err != nil {
    log.Fatalf(&quot;could not load config: %v&quot;, err)
  }
  return &amp;amp;cfg
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code defines a &lt;code&gt;Config&lt;/code&gt; struct that includes three configuration values, namely &lt;code&gt;Debug&lt;/code&gt;, &lt;code&gt;PostgresDSN&lt;/code&gt;, and &lt;code&gt;Port&lt;/code&gt;. The &lt;code&gt;LoadConfig&lt;/code&gt; function uses &lt;code&gt;godotenv&lt;/code&gt; to load any values specified in a local &lt;code&gt;.env&lt;/code&gt; file (if one exists), and &lt;code&gt;envconfig&lt;/code&gt; to populate the &lt;code&gt;Config&lt;/code&gt; struct with any environment variables that match the struct tags.&lt;/p&gt;
&lt;p&gt;Once you&apos;ve successfully loaded your configuration struct, you can initialize your config as follows:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
  cfg := LoadConfig()
  fmt.Println(cfg.PostgresDSN)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;main.go&lt;/code&gt; simply calls &lt;code&gt;LoadConfig&lt;/code&gt; and prints out the value of the &lt;code&gt;PostgresDSN&lt;/code&gt; configuration variable.&lt;/p&gt;
&lt;p&gt;By leveraging environment variables and these two Go packages, you can create more portable, scalable, and secure applications that can be easily configured for different environments.&lt;/p&gt;
</content:encoded></item></channel></rss>