Executando verificação de segurança...
1

Como carregar arquivos .env em Go usando apenas a Standard Library (sem dependências)

Muitas vezes adicionamos dependências externas como o godotenv por hábito, mas o Go oferece ferramentas poderosas na biblioteca padrão que tornam essa tarefa simples e educativa.

Criei um pacote minimalista chamado dotenv que resolve os principais problemas de parsing: suporte a export, remoção de comentários e tratamento de aspas.

1. O utilitário de limpeza (utils.go)

O segredo para um .env robusto é como tratamos o valor. Esta função lida com aspas e remove comentários in-line (ex: KEY="valor" # comentário).

package dotenv

import "strings"

func quotes(value string) string {
    if len(value) == 0 {
        return ""
    }

    // Se começar com aspas, busca o par correspondente
    quote := value[0]
    if quote == '"' || quote == '\'' {
        content, _, found := strings.Cut(value[1:], string(quote))
        if found {
            return content
        }
        value = value[1:] // Caso não ache o par, remove a aspa inicial
    }

    // Remove comentários in-line e limpa espaços
    value, _, _ = strings.Cut(value, "#")
    return strings.TrimSpace(value)
}

2. A lógica principal (dotenv.go)

Aqui percorremos os arquivos e injetamos as variáveis no processo usando os.Setenv.

package dotenv

import (
    "fmt"
    "os"
    "strings"
)

var FilenameVariables = []string{".env", ".env.local"}

func Collect() {
    for _, filename := range FilenameVariables {
        content, err := os.ReadFile(filename)
        if err != nil {
            continue // Pula se o arquivo não existir
        }

        for _, line := range strings.Split(string(content), "\n") {
            line = strings.TrimSpace(line)
            
            // Suporte a prefixo 'export ' (comum em shell scripts)
            line = strings.TrimPrefix(line, "export ")
            
            // Pula linhas vazias ou comentários
            if line == "" || strings.HasPrefix(line, "#") {
                continue
            }

            // Separa Chave=Valor de forma eficiente
            key, value, found := strings.Cut(line, "=")
            if !found {
                continue
            }

            value = quotes(value)
            os.Setenv(key, value)
            
            // Opcional: Log para debug (recomendo remover em produção)
            // fmt.Printf("Loaded: %s\n", key)
        }
    }
}

Por que usar strings.Cut?

Introduzido no Go 1.18, o strings.Cut é superior ao strings.Split para este caso porque:

  1. É mais rápido e aloca menos memória.
  2. Garante que você só divida na primeira ocorrência do =, permitindo que o valor contenha outros símbolos de igual (ex: chaves de API).

Exemplo de uso

Basta chamar o Collect no início do seu main.go:

func main() {
    dotenv.Collect()
    
    apiKey := os.Getenv("API_KEY")
    // ...
}

Conclusão:
Para projetos pequenos e médios, reduzir a árvore de dependências facilita a manutenção e a auditoria de segurança. O que você acha de implementar seus próprios utilitários em vez de inflar o go.mod?

Carregando publicação patrocinada...
1

Porque não simplesmente injetar as variáveis do .env no env da máquina?

No vscode tem uma extensão que injeta o .env no terminal do VSCode

Se rodar com dokcer tem a opção --env-file que injeta automaticamente as variáveis

Com essas abordagens não precisa ler o arquivo, é só ler direto do env.