author
Kevin Kelche

A Guide to INI in Golang


Introduction

INI files are a popular and simple file format for storing configuration data. It consists of sections, which contain key-value pairs, making it easy to organize and read. Unlike other programming languages which have built-in support for INI files, Golang does not and relies on third-party packages to parse and write INI files.

In this guide, we will explore go-ini/ini, a popular package for working with INI files in Golang. We’ll cover the basics of installing and using Golang INI and more advanced features like custom struct tags. By the end of this article, you’ll have a solid understanding of how to work with INI files in Golang using the Golang INI package.

INI Syntax

INI files can have sections, which contain key-value pairs. The syntax for an INI file is as follows:

config.ini
[section]
key = value

Copied!

Example

Let’s take a look at an example INI file:

config.ini
[database]
host = localhost
port = 5432
username = postgres
password = password
[database.options]
sslmode = disable

Copied!

Installing Golang INI

To install the Golang INI package, run the following command:

Terminal
go get gopkg.in/ini.v1

Copied!

Reading INI Files

The ini package provides a Load function that takes a file path and returns a *ini.File object. This object contains all the sections and key-value pairs in the INI file.

main.go
package main

import (
 "fmt"
 "os"

 "gopkg.in/ini.v1"
)

func main() {
 inidata, err := ini.Load("config.ini")
 if err != nil {
    fmt.Printf("Fail to read file: %v", err)
    os.Exit(1)
  }
 section := inidata.Section("database")

  fmt.Println(section.Key("host").String())
  fmt.Println(section.Key("port").String())
  fmt.Println(section.Key("username").String())
  fmt.Println(section.Key("password").String())

 section = inidata.Section("database.options")
  fmt.Println(section.Key("sslmode").String())
}

Copied!

In this example, we use the Load function to read the config.ini file. We then use the Section method to get the database section. We then use the Key method to get the keys in the database section. Finally, we use the String method to get the value of each key.

Writing INI Files

The ini package provides a SaveTo function that takes a file path and writes the *ini.File object to the file.

main.go
package main

import (
 "gopkg.in/ini.v1"
)

// Writing INI files
func main() {
 inidata := ini.Empty()
 sec, err := inidata.NewSection("database")
 if err != nil {
 panic(err)
  }
 _, err = sec.NewKey("host", "localhost")
 if err != nil {
 panic(err)
  }

 sec, err = inidata.NewSection("database.options")
 if err != nil {
 panic(err)
  }

 _, err = sec.NewKey("sslmode", "disable")
 if err != nil {
 panic(err)
  }

 err = inidata.SaveTo("config2.ini")
 if err != nil {
 panic(err)
  }

}

Copied!

In this example, we use the Empty function to create a new *ini.File object. We then use the NewSection method to create a new section. We then use the NewKey method to create a new key in the section. Finally, we use the SaveTo method to write the *ini.File object to the config2.ini file.

This function is also used to update an existing INI file.

main.go
section := inidata.Section("database")

  section.Key("host").SetValue("127.0.0.0")
  section.Key("port").SetValue("3306")

 err = inidata.SaveTo("config.ini")
 if err != nil {
 panic(err)
  }

Copied!

Working with Structs

The ini package provides a MapTo function that takes a struct and maps the keys in the INI file to the struct fields.

main.go
package main

import (
 "fmt"
 "os"

 "gopkg.in/ini.v1"
)

type Config struct {
  Database struct {
    Host     string `ini:"host"`
    Port     int `ini:"port"`
    Username string `ini:"username"`
    Password string `ini:"password"`
  } `ini:"database"`
  Options struct {
    SSLMode string `ini:"sslmode"`
  } `ini:"database.options"`
}

func main() {
 inidata, err := ini.Load("config.ini")
 if err != nil {
    fmt.Printf("Fail to read file: %v", err)
    os.Exit(1)
  }

 var config Config

 err = inidata.MapTo(&config)
 if err != nil {
    fmt.Printf("Fail to map file: %v", err)
    os.Exit(1)
  }

  fmt.Println(config.Database.Host)
  fmt.Println(config.Database.Port)
  fmt.Println(config.Database.Username)

  fmt.Println(config.Options.SSLMode)
}

Copied!

In the above code, we use the MapTo function to map the keys in the INI file to the struct fields. We then use the ini struct tags to map the keys to the struct fields.

Type Conversion

The Key struct provides various methods used for explicit type conversion.

indata.Section("database").Key("port").Int()
indata.Section(database.options").Key("sslmode").Bool()

Copied!

This is useful when the value in the INI file is not the same type as the struct field. For example, if the port key in the INI file is a string, but the Port field in the struct is an integer, we can use the Int method to convert the value to an integer. We can also use MustInt to convert the value to an integer and return a default value if the conversion fails. The Must.. methods are helpful when the value in the INI file is optional.

indata.Section("database").Key("port").MustInt(5432)

Copied!

Conclusion

In this article, we looked at how to read and write INI files in Golang using the ini package. We also looked at how to map INI keys to struct fields. Check out the documentation for more features.

Subscribe to my newsletter

Get the latest posts delivered right to your inbox.