A pergunta mais comum de quem busca a primeira vaga em Go não é “qual framework aprender”. É “o que eu coloco no portfólio?”. E a resposta que mais ajuda não é uma lista de ideias genéricas — é entender o que um projeto precisa demonstrar para que um recrutador ou um engenheiro sênior pense: “essa pessoa sabe levar um serviço até o fim”.
O mercado brasileiro de Go aparece muito em empresas com produto em produção: fintech, pagamentos, logística, plataformas internas, microsserviços e infraestrutura. Por isso, o portfólio ideal não é uma coleção de tutoriais copiados. É um sistema pequeno, porém completo, que se parece com trabalho real. Este guia mostra cinco projetos em Go para portfólio que sustentam uma conversa técnica de verdade em 2026, com o que cada um demonstra, a stack envolvida e como estruturar o repositório. Se você está começando do zero, vale seguir antes o Roadmap Go 2026 para não pular etapas.
O que um projeto de portfólio Go precisa demonstrar
Antes de escolher a ideia, entenda os sinais que um avaliador procura. Um bom projeto mostra, ao mesmo tempo, alguns destes pontos:
- Ciclo completo de um serviço: receber uma requisição HTTP, validar dados, persistir em banco, responder de forma padronizada e tratar erros sem esconder falhas.
- Banco de dados real: PostgreSQL com migrations, e não só um map em memória.
- Testes: ao menos testes de tabela cobrindo os caminhos felizes e os de erro.
- Empacotamento: Dockerfile enxuto e um comando para rodar tudo.
- Decisões explicadas: um README que diz o quê e por quê.
- Concorrência consciente: quando fizer sentido, goroutines, channels e context com cancelamento.
Note que “saber o framework da moda” não está na lista. O que transfere entre empresas e entre frameworks é o domínio de net/http, context, tratamento de erro, testes e padrões de produção. O guia de Go para backend aprofunda esses fundamentos.
Projeto 1: API REST com autenticação, testes e Docker
É o projeto-base. Se você só tiver tempo para um, faça este. A proposta é construir uma API REST pequena (um gerenciador de tarefas, um controle financeiro pessoal, um agregador de vagas) com autenticação, persistência em PostgreSQL, testes e um Dockerfile.
O que ela demonstra: roteamento, validação de entrada, tratamento de erro padronizado, uso de PostgreSQL com Go, migrations e testes de tabela. Para a autenticação, JWT é um padrão de mercado; o tutorial de autenticação em APIs Go cobre o caminho.
Um esboço de handler com tratamento de erro explícito:
package main
import (
"encoding/json"
"errors"
"net/http"
"strconv"
)
type Servico struct {
repo *Repositorio
}
func (s *Servico) CriarTarefa(w http.ResponseWriter, r *http.Request) {
var entrada struct {
Titulo string `json:"titulo"`
}
if err := json.NewDecoder(r.Body).Decode(&entrada); err != nil {
responderErro(w, http.StatusBadRequest, "payload inválido")
return
}
if entrada.Titulo == "" {
responderErro(w, http.StatusBadRequest, "título é obrigatório")
return
}
tarefa, err := s.repo.Criar(r.Context(), entrada.Titulo)
if err != nil {
responderErro(w, http.StatusInternalServerError, "falha ao salvar")
return
}
responderJSON(w, http.StatusCreated, tarefa)
}
// responderErro e responderJSON centralizam o formato de resposta.
func responderJSON(w http.ResponseWriter, status int, corpo any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(corpo)
}
func responderErro(w http.ResponseWriter, status int, msg string) {
responderJSON(w, status, map[string]string{"erro": msg})
}
var _ = errors.New
var _ = strconv.Atoi
Atenção: o trecho acima é um esqueleto para ilustrar o padrão de handler com erro centralizado. A classe
Repositorioe a conexão com o banco ficam por sua conta — veja o tutorial de API REST com Go para a versão completa, e a série de API REST com Gin se preferir framework.
Dica de ouro: padronize as respostas de erro. Misturar {"erro": "..."} em uma rota com {"message": "..."} em outra passa o sinal de que o código não tem convenção — e isso aparece em code review.
Projeto 2: Worker pool com fila de processamento assíncrono
Esse projeto separa o seu portfólio de quem só fez CRUD. A ideia: um serviço que recebe jobs (processar uma imagem, enviar um e-mail, gerar um relatório) e executa em background com um número controlado de workers, usando concorrência de verdade.
O que demonstra: goroutines, channels, context com cancelamento e timeout, graceful shutdown (não derrubar jobs no meio quando o processo morre) e noções de fila. O guia de worker pool em Go mostra a estrutura completa; o artigo sobre channels em Go aprofunda a comunicação entre goroutines.
Um padrão compacto de worker pool com cancelamento via contexto:
package main
import (
"context"
"fmt"
"sync"
"time"
)
type Job struct {
ID int
}
func worker(ctx context.Context, jobs <-chan Job, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
select {
case <-ctx.Done():
return // contexto cancelado: pare de forma limpa
default:
processar(ctx, j)
}
}
}
func processar(ctx context.Context, j Job) {
// simula trabalho respeitando o contexto
select {
case <-time.After(200 * time.Millisecond):
fmt.Printf("job %d concluído\n", j.ID)
case <-ctx.Done():
fmt.Printf("job %d interrompido\n", j.ID)
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
jobs := make(chan Job, 10)
var wg sync.WaitGroup
for w := 0; w < 3; w++ {
wg.Add(1)
go worker(ctx, jobs, &wg)
}
for i := 0; i < 5; i++ {
jobs <- Job{ID: i}
}
close(jobs)
wg.Wait()
}
Para subir o nível, troque o channel em memória por uma fila real: Redis Streams, SQS na AWS ou RabbitMQ. Isso mostra que você entende filas distribuídas, e não só concorrência dentro de um processo.
Projeto 3: Serviço gRPC ou gateway com observabilidade
Go brilha em comunicação entre serviços internos, e gRPC é o padrão para isso. Um projeto forte é um serviço gRPC (definido em Protobuf) que expõe algumas operações, instrumentado com tracing e métricas. Alternativamente, um gateway HTTP que chama um serviço gRPC interno.
O que demonstra: gRPC com Protobuf, definição de contratos, observabilidade com OpenTelemetry (traces distribuídos) e a diferença entre APIs internas (gRPC) e externas (HTTP/JSON). É um diferencial que aparece muito em vagas de microsserviços e plataformas.
Mesmo sem gRPC, você pode adicionar observabilidade ao Projeto 1: instrumentar a API REST com OpenTelemetry e expor métricas no formato Prometheus. Um serviço com /metrics e tracing já fica visivelmente mais “produção” do que 90% dos portfólios.
Projeto 4: CLI com cobra
Nem todo projeto precisa ser servidor. Uma ferramenta de linha de comando é um portfólio excelente e menos óbvio: mostra que você entende a linguagem para além de HTTP. Ideias: um gerador de senhas, um CLI que consome uma API pública, uma ferramenta de linha de comando para buscar e filtrar as próprias vagas de Go, ou um utilitário que processa arquivos em lote.
O que demonstra: organização de pacotes, módulos Go, flags e subcomandos, leitura/escrita de arquivos e testes de funções puras. Use a biblioteca cobra — é o padrão de mercado para CLIs em Go (é o que o próprio go e ferramentas como hugo, docker e kubectl usam por baixo).
package main
import (
"fmt"
"strconv"
"github.com/spf13/cobra"
)
func main() {
root := &cobra.Command{
Use: "meucli",
Short: "Exemplo de CLI em Go para portfólio",
}
dobro := &cobra.Command{
Use: "dobro [número]",
Short: "Calcula o dobro de um número",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
n, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("argumento inválido: %w", err)
}
fmt.Println(n * 2)
return nil
},
}
root.AddCommand(dobro)
_ = root.Execute()
}
Uma CLI pequena, com --help organizado e testes, é um projeto rápido que se sustenta sozinho — e rende assunto em entrevista porque força você a pensar em ergonomia e tratamento de erro.
Projeto 5: Encurtador de links com cache Redis
Clássico, mas eficaz quando bem feito. A ideia: uma API que encurta URLs e, no redirecionamento, usa cache (Redis) para responder rápido sem bater no banco a cada acesso.
O que demonstra: cache com Redis, separação entre camada de cache e persistência, métricas de latência e trade-offs (invalidação de cache, expiração). É um projeto curto, com um problema de performance real para discutir: como o sistema se comporta com milhares de acessos ao mesmo link?
Para fechar o ciclo de produção, adicione rate limiting e um health check no estilo liveness/readiness. São dois detalhes pequenos que mostram maturidade operacional.
Como estruturar o repositório e o README
Um projeto de portfólio bem estruturado vence um projeto melhor escrito, mas bagunçado. Use uma organização de pastas que se pareça com código real:
meu-projeto/
├── cmd/
│ └── server/
│ └── main.go # ponto de entrada
├── internal/
│ ├── handler/ # handlers HTTP
│ ├── service/ # regras de negócio
│ ├── repository/ # acesso a dados
│ └── model/ # entidades
├── migrations/ # SQL de migração
├── Dockerfile
├── docker-compose.yml # sobe app + postgres + redis
├── go.mod
└── README.md
O README é a parte mais importante. Um recrutador ou sênior decide em dois minutos se vai ler o código. Um bom README responde:
- O que o sistema faz em três linhas.
- Decisões técnicas e por quê. Por que PostgreSQL e não SQLite? Por que
net/httpe não Gin? Justificar escolhas mostra maturidade. - Como rodar localmente com um comando só (
docker compose up). - Estrutura de pastas e o que cada pacote faz.
- Endpoints ou comandos disponíveis, com exemplos de requisição.
- Como rodar os testes (
go test ./...).
Não invente números de performance (“suporta 10 mil requisições por segundo”) sem medir. Se for medir de verdade, use o guia de profiling e performance com pprof e coloque o método no README.
Como apresentar o projeto na entrevista
Ter o projeto é metade; saber falar dele é a outra. Em entrevista técnica, prepare-se para explicar:
- O fluxo de uma requisição do início ao fim: o que acontece entre o cliente bater no endpoint e a resposta sair.
- As decisões de design e suas alternativas. “Usei um worker pool com buffer 10 porque…” é uma frase que impressiona; “usei goroutines” não.
- Os trade-offs. Cache acelera leitura, mas adiciona invalidação. Fila desacopla, mas adiciona complexidade.
- O que você faria diferente com mais tempo. Honestidade sobre o que falta vale pontos.
O guia de entrevista técnica em Go lista as perguntas mais frequentes e como se preparar. Para o currículo, o guia de currículo de desenvolvedor Go mostra como destacar o portfólio sem inflar.
Erros comuns no portfólio Go
- Repositório sem README, ou com um README de uma linha. É a primeira coisa que eliminam.
- Código sem teste algum. Mesmo poucos testes de tabela já mudam a percepção.
- Tratamento de erro que esconde falhas (
_ = errouif err != nil { return }sem contexto). Em Go, o jeito como você trata erro é uma assinatura de senioridade. - Dependências sem gerenciamento. Sem
go.sumorganizado ou com vulnerabilidades conhecidas. Rodegovulncheckantes de publicar. - Muitos repositórios rasos. Dez “hello world” valem menos que um projeto sólido. Concentre esforço.
- Segredos no repositório. Nenhuma chave de API no código. Use variáveis de ambiente e
.env.example.
Próximos passos: do portfólio à vaga
Escolha um projeto principal entre os cinco acima e leve até o fim: testes, Docker, README honesto e, se possível, deploy. Depois, coloque o link do repositório em destaque no currículo e comece a aplicar. As vagas de Go no Brasil mostram o que o mercado pede em termos de senioridade, regime (CLT ou PJ) e localização — e o guia de como conseguir a primeira vaga em Go fecha o funil, do perfil exigido ao plano de 90 dias.
O portfólio não precisa ser perfeito nem cobrir tudo. Precisa mostrar que você entende o ciclo de um serviço e consegue explicar o que construiu. Esse conjunto — um projeto sólido e a capacidade de falar sobre ele — vale mais do que conhecer a API de cada framework. Para quem quer comparar como o mesmo desafio de “portfólio de entrada” aparece em outra linguagem, o portal de vagas eu.dev.br reúne oportunidades de desenvolvimento no Brasil e ajuda a calibrar o que cada stack pede de portfólio.