{"id":18077521,"url":"https://github.com/snaipe/boa","last_synced_at":"2025-10-13T00:24:27.777Z","repository":{"id":44762678,"uuid":"448912808","full_name":"Snaipe/boa","owner":"Snaipe","description":"Better configuration management in Go","archived":false,"fork":false,"pushed_at":"2024-12-06T09:33:01.000Z","size":195,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-19T15:56:17.582Z","etag":null,"topics":["config","configuration","configuration-management","go","golang","json5","no-dependencies","toml"],"latest_commit_sha":null,"homepage":"https://snai.pe/boa","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Snaipe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["Snaipe"],"custom":["https://paypal.me/snaipewastaken"]}},"created_at":"2022-01-17T13:51:04.000Z","updated_at":"2025-03-20T15:20:35.000Z","dependencies_parsed_at":"2025-04-12T10:11:40.263Z","dependency_job_id":"cf6abd7a-594e-47c0-b9da-a12900cce966","html_url":"https://github.com/Snaipe/boa","commit_stats":{"total_commits":99,"total_committers":2,"mean_commits":49.5,"dds":0.02020202020202022,"last_synced_commit":"d47e5ee83dd40eadfcec5ed033dc2eb1e8093a9f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Snaipe/boa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snaipe%2Fboa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snaipe%2Fboa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snaipe%2Fboa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snaipe%2Fboa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Snaipe","download_url":"https://codeload.github.com/Snaipe/boa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snaipe%2Fboa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013633,"owners_count":26085298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["config","configuration","configuration-management","go","golang","json5","no-dependencies","toml"],"created_at":"2024-10-31T11:45:00.221Z","updated_at":"2025-10-13T00:24:27.756Z","avatar_url":"https://github.com/Snaipe.png","language":"Go","funding_links":["https://github.com/sponsors/Snaipe","https://paypal.me/snaipewastaken"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\u003ch1\u003e\u003cimg src=\"assets/title.svg\" height=\"200\" alt=\"Boa Logo\" /\u003e\u003c/h1\u003e\u003c/div\u003e\n\nA friendlier viper.\n\n[![Builds](https://img.shields.io/github/workflow/status/Snaipe/boa/Test)](https://github.com/Snaipe/boa/actions/workflows/test.yml)\n[![GoDoc](https://godoc.org/snai.pe/boa?status.svg)](https://godoc.org/snai.pe/boa)\n[![GitHub](https://img.shields.io/github/license/Snaipe/boa?color=brightgreen)](LICENSE)\n[![Dependencies](https://img.shields.io/badge/dependencies-none!-brightgreen)](go.mod)\n\n```\ngo get snai.pe/boa\n```\n\n## Introduction\n\nBoa aims to be a **simple, human-focused, no-dependency** configuration management library.\n\nIt supports **JSON5** and **TOML**.\n\nConfigurations are expressed as Go types, using struct field tags to map configuration files\nto type-safe data types.\n\nFor instance, the following TOML configuration file:\n\n```toml\n[person]\nfirst-name = \"John\"\nlast-name = \"Doe\"\ndob = 1953-02-25T00:00:42-08:00\n```\n\nCan be loaded into this Go type:\n\n```go\ntype Config struct {\n  Person struct {\n    FirstName string\n    LastName  string\n    Birth     time.Time `name:\"dob\"`\n  } `naming:\"kebab-case\"`\n}\n```\n\n## Why boa?\n\nAt the time of writing, none of the other configuration parsers are actually designed\nfor configuration. Most of the standard parsers under the `encoding` package are\ndesigned for robots. Non-standard parsers either do not follow the same semantics\nas the standard packages, or suffer the same flaws as standard parsers. Comments\nand formatting are usually not parsed nor preserved. Encoders interact poorly\nwith other encoders, usually necessitating multiple struct tags per configuration\nlanguage, or do not provide a good interface for accessing and discovering\nconfiguration values.\n\nBoa aims to be an overall better configuration management library. It has _no_\ndependencies outside of the standard Go library, and provides a unified way to load,\nmanipulate, and save configurations.\n\nThe following languages are supported:\n\n* JSON5\n* TOML\n\nIn addition, all configuration parsers have the following properties:\n\n* Error messages contain the filename when available as well as the line and column\n  number where the error occured.\n* Parsers support the same set of base struct tags for consistency and conciseness.\n* Comments and whitespace are preserved by the parsers in the configuration AST,\n  which makes it possible to edit configuration while still preserving the style\n  of the original file.\n\n## Supported tags\n\n\u003c!--\nNOTE: The values in the Tag column below contain an invisible word-joiner character\n(U+2060) after the first double-quote (\") character. This is done to prevent\nany unfortunate line breaks in the middle of the escaped value, but might mess up\nsome editors.\n\nTo insert these characters in vim, position the cursor where the character needs\nto be inserted, enter insert mode, press Ctrl-V, then u2060.\n--\u003e\n\n| Tag               | Description\n|-------------------|-------------\n| `name:\"⁠\u003cname\u003e\"`   | Set key name.\n| `help:\"⁠\u003chelp\u003e\"`   | Set documentation; appears as comment in the config.\n| `naming:\"⁠\u003cname\u003e\"` | Set naming convention for key and subkeys.\n| `env:\"⁠\u003cvar\u003e\"`     | Populate field with specified environment variable.\n| `inline`          | Inline field. All sub-fields will be treated as if they were in the containing struct itself. Does the same as embedding the field.\n| `-`               | Ignore field.\n\n## Supported types\n\nAny type that implements [`encoding.TextMarshaler`][encoding.TextMarshaler] can be saved as a string.\nAny type that implements [`encoding.TextUnmarshaler`][encoding.TextUnmarshaler] can be loaded from a string.\n\nIn addition, the following standard library types are marshaled and unmarshaled as the appropriate type:\n\n| Type                 | Treated as |\n|----------------------|------------|\n| `[]byte`             | String     |\n| `*big.Int`           | Number     |\n| `*big.Float`         | Number     |\n| `*big.Rat`           | Number     |\n| `time.Time`          | String     |\n| `*url.URL`           | String     |\n| `*regexp.Regexp`     | String     |\n\nSome packages also define or support some specialized types for specific configuration objects:\n\n| Type                 | Treated as | Packages (under `snai.pe/boa/encoding`)\n|----------------------|------------|-----------------------------------------\n| `time.Time`          | DateTime   | `toml`\n| `toml.LocalDateTime` | DateTime   | `toml`\n| `toml.LocalDate`     | DateTime   | `toml`\n| `toml.LocalTime`     | DateTime   | `toml`\n\n## Examples\n\n### Loading configuration\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"snai.pe/boa\"\n)\n\nfunc main() {\n\n\tvar config struct {\n\t\tAnswer   int               `help:\"This is an important field that needs to be 42\"`\n\t\tPrimes   []int             `help:\"Some prime numbers\"`\n\t\tContacts map[string]string `help:\"Some people in my contact list\"`\n\t}\n\n\t// Will load any matching \"appname.toml\" config file from the system config path,\n\t// then the user config path. The TOML decoder is inferred from the .toml extension.\n\t//\n\t// For instance, on Linux, this will load in order:\n\t//     - /etc/\u003cappname\u003e.toml\n\t//     - /etc/xdg/\u003cappname\u003e.toml\n\t//     - ~/.config/\u003cappname\u003e.toml\n\t//\n\tif err := boa.Load(\"appname\", \u0026config); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n```\n\n### Loading configuration, with defaults\n\nConfiguration defaults are not, by design, set via struct tags or other field-specific mechanisms.\n\nInstead, write a default configuration file in your package, and embed it. Multiple configs\ndefaults can be embedded into the same embed.FS declaration -- see the documentation of\nthe [embed](https://pkg.go.dev/embed) package.\n\n```golang\npackage main\n\nimport (\n\t\"embed\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"snai.pe/boa\"\n)\n\n//go:embed appname.toml\nvar defaults embed.FS\n\nfunc main() {\n\n\t// Register defaults\n\tboa.SetDefaults(defaults)\n\n\tvar config struct {\n\t\tAnswer   int               `help:\"This is an important field that needs to be 42\"`\n\t\tPrimes   []int             `help:\"Some prime numbers\"`\n\t\tContacts map[string]string `help:\"Some people in my contact list\"`\n\t}\n\n\tif err := boa.Load(\"appname\", \u0026config); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n}\n```\n\nGood configuration defaults should be consistent and self-explanatory. Consider making\nthe default for fields their respective type's zero value.\n\n### Environment variables\n\nConfiguration fields can be explicitly bound to environment variables via the `env` struct tag:\n\n```golang\ntype Config struct {\n\tShell string   `env:\"SHELL\"`\n\tPath  []string `env:\"PATH\"`\n}\n```\n\nEnvironment values are generally parsed according to the strconv Parse functions, or using\nUnmarshalText if the field's type implements encoding.TextUnmarshaler.\n\nSlices and arrays are parsed as a path-list-separated list of strings. The delimiter\nis os.PathListSeparator: with the above example, on Unix derivatives, `PATH=a:b:c` would\nget unmarshaled as [a, b, c], while on Windows the value would need to be `PATH=a;b;c`.\n\nFields with no `env` tag are not populated from the environment, unless the AutomaticEnv\noption is provided:\n\n```golang\ntype Config struct {\n\tImplicitVariable string\n}\n\nboa.SetOptions(\n\tboa.AutomaticEnv(\"PREFIX\"),\n)\n```\n\nIn this example, `PREFIX_IMPLICIT_VARIABLE=value` would set `Config.ImplicitVariable`.\n\n## Credits\n\nLogo made by [Irina Mir](https://twitter.com/irmirx)\n\n[encoding.TextMarshaler]: https://pkg.go.dev/encoding#TextMarshaler\n[encoding.TextUnmarshaler]: https://pkg.go.dev/encoding#TextUnmarshaler\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnaipe%2Fboa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnaipe%2Fboa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnaipe%2Fboa/lists"}