5 proyectos reales para aprender Go si ya sabes programar

Proyectos prácticos para aprender Go: CLI, API REST, worker, consumidor Kafka y conversor de ficheros. Con enlaces a tutoriales paso a paso.

Cover for 5 proyectos reales para aprender Go si ya sabes programar

Los ejercicios de sintaxis no sirven. Haces veinte problemas de bucles, tres de slices, uno de interfaces, y al día siguiente no recuerdas nada. No porque seas mal estudiante, sino porque el cerebro no retiene lo que no tiene contexto. Y la sintaxis de Go fuera de un problema real no tiene contexto.

La forma de aprender Go de verdad es construir cosas pequeñas que resuelvan problemas reales. No un TODO app. No un “Hello World con goroutines”. Proyectos que se parezcan a lo que harías en tu trabajo o en un servicio que desplegarías en producción.

Llevo meses escribiendo tutoriales paso a paso sobre Go, cada uno centrado en un proyecto concreto. Este artículo es el mapa. Aquí te explico qué cinco proyectos construir, en qué orden, qué vas a aprender con cada uno, y por qué ese orden importa.


Por qué proyectos > tutoriales para aprender Go

Hay una diferencia enorme entre leer documentación y resolver un problema. Cuando lees sobre goroutines, entiendes el concepto. Cuando tienes que paralelizar diez peticiones HTTP y agregar resultados con un timeout, aprendes goroutines.

Esto aplica a cualquier lenguaje, pero en Go es especialmente cierto por dos razones:

  1. Go es minimalista por diseño. No tiene cien formas de hacer lo mismo. Eso significa que los patrones correctos los interiorizas rápido, pero solo si los usas en contexto. Leerlos no basta.
  2. El tooling de Go es parte del lenguaje. go test, go build, go mod, go vet… No son extras. Son fundamentales. Y solo los aprendes usándolos en un proyecto con estructura real.

La trampa clásica es intentar aprender Go leyendo Effective Go de principio a fin, o completando un curso de sintaxis de cuatro horas. Terminas sabiendo que existen los channels pero sin haber escrito uno que resuelva algo. Sabes que defer existe pero no has sentido por qué importa en un handler HTTP que abre y cierra conexiones.

Los cinco proyectos que propongo aquí están diseñados para cubrir el espectro de lo que necesita un desarrollador backend. Cada uno ataca un dominio diferente y te fuerza a usar una combinación distinta de herramientas del lenguaje.


Proyecto 1: CLI para automatización local

Qué construyes: Una herramienta de línea de comandos que automatiza una tarea repetitiva. Puede ser renombrar ficheros, limpiar logs, generar reportes, lo que quieras. Lo importante es que reciba argumentos, procese algo y devuelva un resultado.

Por qué este primero: Porque elimina todas las distracciones. No hay HTTP, no hay base de datos, no hay Docker. Solo tú, el lenguaje y el sistema operativo. Es el terreno perfecto para asentar los fundamentos.

Qué vas a aprender

  • Estructura básica de un proyecto Go con go mod init
  • Cómo parsear argumentos con os.Args o librerías como cobra
  • Manejo de ficheros: leer, escribir, recorrer directorios
  • El patrón de error handling de Go (if err != nil)
  • Compilar un binario y distribuirlo

Ejemplo mínimo

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	if len(os.Args) < 3 {
		fmt.Println("uso: renombrar <directorio> <prefijo>")
		os.Exit(1)
	}

	dir := os.Args[1]
	prefix := os.Args[2]

	entries, err := os.ReadDir(dir)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error leyendo directorio: %v\n", err)
		os.Exit(1)
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		oldPath := filepath.Join(dir, entry.Name())
		newPath := filepath.Join(dir, prefix+"_"+entry.Name())
		if err := os.Rename(oldPath, newPath); err != nil {
			fmt.Fprintf(os.Stderr, "error renombrando %s: %v\n", oldPath, err)
			continue
		}
		fmt.Printf("%s -> %s\n", oldPath, strings.TrimPrefix(newPath, dir+"/"))
	}
}

Esto es un CLI real. No es sofisticado, pero ya tienes argumentos, manejo de errores, operaciones con el filesystem y un binario que funciona. Desde aquí puedes añadir flags, validaciones, output formateado, tests.

Tutorial completo: CLI en Go


Proyecto 2: API REST con estructura profesional

Qué construyes: Una API REST con endpoints CRUD, conexión a base de datos, validación de datos y una estructura de carpetas que escale. No una API de juguete con un map en memoria: una API con PostgreSQL, migraciones y tests.

Por qué este segundo: Porque después de la CLI ya dominas la base del lenguaje. Ahora toca aprender cómo Go maneja HTTP, JSON, middleware y todo lo que rodea al desarrollo web backend.

Qué vas a aprender

  • El paquete net/http y cómo funciona un server en Go
  • Routing con el mux estándar o con frameworks como Gin
  • Serialización y deserialización JSON con struct tags
  • Conexión a PostgreSQL con database/sql o sqlx
  • Organización de código: handlers, services, repositories
  • Middleware para logging, autenticación, CORS
  • Testing de endpoints con httptest

Ejemplo: handler básico

func GetTaskHandler(db *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id := r.PathValue("id")

		var task Task
		err := db.QueryRow(
			"SELECT id, title, done FROM tasks WHERE id = $1", id,
		).Scan(&task.ID, &task.Title, &task.Done)

		if err == sql.ErrNoRows {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		if err != nil {
			http.Error(w, "internal error", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(task)
	}
}

Fíjate en lo que no hay: no hay framework mágico que esconda el request y el response. No hay anotaciones. No hay inyección de dependencias automática. En Go ves exactamente lo que pasa en cada línea. Eso es incómodo al principio y una ventaja enorme cuando algo falla en producción.

Si quieres un proyecto más completo con PostgreSQL y Docker incluido, tengo un tutorial específico: API de tareas con Go, PostgreSQL y Docker.

Tutorial de la API: API REST con Go


Proyecto 3: Worker de procesamiento en background

Qué construyes: Un servicio que recoge tareas de una cola (puede ser Redis, una tabla en PostgreSQL o un canal en memoria) y las procesa en segundo plano. Redimensionar imágenes, enviar emails, generar PDFs, lo que encaje con tu caso.

Por qué este tercero: Porque aquí es donde Go empieza a brillar. Las goroutines y los channels dejan de ser teoría y se convierten en la herramienta que usa tu worker para procesar N tareas en paralelo sin reventar la memoria.

Qué vas a aprender

  • Goroutines y channels en un escenario real
  • El patrón worker pool
  • context.Context para cancelación y timeouts
  • sync.WaitGroup para esperar a que terminen los workers
  • Graceful shutdown con señales del sistema operativo
  • Logging estructurado

Ejemplo: worker pool básico

func startWorkers(ctx context.Context, jobs <-chan Job, results chan<- Result, numWorkers int) {
	var wg sync.WaitGroup

	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func(workerID int) {
			defer wg.Done()
			for {
				select {
				case <-ctx.Done():
					log.Printf("worker %d: shutting down", workerID)
					return
				case job, ok := <-jobs:
					if !ok {
						return
					}
					result := process(job)
					results <- result
				}
			}
		}(i)
	}

	go func() {
		wg.Wait()
		close(results)
	}()
}

Este patrón es el pan de cada día en servicios Go de producción. Lo vas a ver en procesadores de colas, en pipelines de datos, en cualquier sistema que necesite hacer trabajo pesado sin bloquear el flujo principal.

Lo importante aquí no es solo el código. Es entender cómo context te permite propagar cancelaciones, cómo los channels te dan sincronización sin locks explícitos, y cómo el graceful shutdown evita que tu worker muera a mitad de un procesamiento cuando Kubernetes manda un SIGTERM.

Tutorial completo: worker en Go


Proyecto 4: Consumidor Kafka para procesamiento de eventos

Qué construyes: Un servicio que se suscribe a un topic de Kafka, lee mensajes, los deserializa, los procesa y gestiona offsets y errores. Es el proyecto más cercano a lo que encontrarías en una arquitectura de microservicios real.

Por qué este cuarto: Porque si ya has construido una API y un worker, tienes la base para entender sistemas distribuidos. Kafka añade la complejidad de particiones, consumer groups, offsets y rebalanceos. Y aprender a gestionar todo eso en Go te da un skill directamente aplicable en producción.

Qué vas a aprender

  • Cómo funciona Kafka a nivel de consumidor (topics, particiones, offsets, consumer groups)
  • Uso de librerías como confluent-kafka-go o segmentio/kafka-go
  • Deserialización de mensajes (JSON, Avro, Protobuf)
  • Gestión de errores y reintentos
  • Procesamiento idempotente
  • Métricas y health checks

Ejemplo: consumidor básico

func consume(ctx context.Context, reader *kafka.Reader) error {
	for {
		select {
		case <-ctx.Done():
			return reader.Close()
		default:
			msg, err := reader.ReadMessage(ctx)
			if err != nil {
				if errors.Is(err, context.Canceled) {
					return nil
				}
				log.Printf("error reading message: %v", err)
				continue
			}

			var event OrderCreated
			if err := json.Unmarshal(msg.Value, &event); err != nil {
				log.Printf("error unmarshalling message: %v", err)
				continue
			}

			if err := processOrder(ctx, event); err != nil {
				log.Printf("error processing order %s: %v", event.OrderID, err)
				// Aquí decides: ¿reintentar? ¿enviar a DLQ? ¿loguear y continuar?
				continue
			}

			log.Printf("processed order %s from partition %d offset %d",
				event.OrderID, msg.Partition, msg.Offset)
		}
	}
}

Kafka es una de esas tecnologías que puedes usar durante años sin entender del todo. Construir un consumidor desde cero te obliga a entender qué pasa cuando un consumer se cae y otro toma su partición, qué significa commit manual vs automático de offsets, y por qué el procesamiento idempotente no es opcional.

Tutorial completo: Kafka con Go


Proyecto 5: Conversor CSV a JSON

Qué construyes: Una herramienta que lee ficheros CSV (potencialmente grandes), los parsea, transforma y escribe como JSON. Parece simple. No lo es cuando el CSV tiene millones de filas, encodings raros o campos que no cumplen el esquema esperado.

Por qué este quinto: Porque toca un dominio completamente diferente: procesamiento de datos. Y porque te fuerza a pensar en streaming, en uso de memoria y en cómo Go maneja I/O de forma eficiente.

Qué vas a aprender

  • Paquetes encoding/csv y encoding/json
  • Lectura streaming sin cargar todo en memoria
  • Interfaces io.Reader y io.Writer
  • Buffered I/O con bufio
  • Validación y transformación de datos
  • Testing con ficheros de ejemplo
  • Flags para configurar el comportamiento (delimitador, encoding, output format)

Ejemplo: streaming CSV a JSON

func convertCSVtoJSON(input io.Reader, output io.Writer) error {
	reader := csv.NewReader(input)

	headers, err := reader.Read()
	if err != nil {
		return fmt.Errorf("reading headers: %w", err)
	}

	encoder := json.NewEncoder(output)
	encoder.SetIndent("", "  ")

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("reading record: %w", err)
		}

		row := make(map[string]string, len(headers))
		for i, header := range headers {
			if i < len(record) {
				row[header] = record[i]
			}
		}

		if err := encoder.Encode(row); err != nil {
			return fmt.Errorf("encoding row: %w", err)
		}
	}

	return nil
}

Lo interesante de este proyecto es que trabaja con las interfaces de I/O de Go, que son una de las piezas más elegantes del lenguaje. io.Reader y io.Writer están en todas partes: ficheros, conexiones HTTP, buffers, compresores. Entender cómo componerlas es fundamental.

Además, este proyecto escala naturalmente. Empiezas con un conversor básico y puedes añadir: soporte para ficheros enormes con procesamiento concurrente, detección automática de tipos, output en múltiples formatos (JSON Lines, Parquet), validación contra un esquema.

Tutorial completo: CSV a JSON en Go


Bonus: web scraper con concurrencia

No está en los cinco principales porque el scraping tiene sus propias complicaciones (legales, de infraestructura, de estabilidad), pero como proyecto de aprendizaje es excelente.

Qué construyes: Un scraper que visita una lista de URLs, extrae datos estructurados y los almacena. La gracia está en hacerlo concurrente: lanzar N goroutines, limitar la tasa de peticiones, gestionar errores por URL sin que el sistema entero se caiga.

Qué vas a aprender

  • HTTP client avanzado: timeouts, retries, headers personalizados
  • Concurrencia controlada con semáforos (chan struct{})
  • Rate limiting con time.Ticker
  • Parsing HTML con librerías como goquery
  • Patrones de resiliencia: circuit breaker, backoff exponencial
func scrape(ctx context.Context, urls []string, concurrency int) []Result {
	results := make([]Result, 0, len(urls))
	sem := make(chan struct{}, concurrency)
	var mu sync.Mutex
	var wg sync.WaitGroup

	for _, url := range urls {
		wg.Add(1)
		go func(u string) {
			defer wg.Done()
			sem <- struct{}{}        // adquirir semáforo
			defer func() { <-sem }() // liberar semáforo

			data, err := fetchAndParse(ctx, u)
			mu.Lock()
			defer mu.Unlock()
			if err != nil {
				results = append(results, Result{URL: u, Error: err})
				return
			}
			results = append(results, Result{URL: u, Data: data})
		}(url)
	}

	wg.Wait()
	return results
}

El semáforo con un channel buffered es un patrón que ves constantemente en Go. Es simple, no requiere ninguna librería externa, y te da control preciso sobre cuántas operaciones concurrentes quieres permitir.

Tutorial completo: scraper en Go


Cómo presentar estos proyectos en tu portfolio

Construir los proyectos es solo la mitad. La otra mitad es que alguien pueda mirar tu GitHub y entender qué hiciste y por qué. Esto aplica tanto si buscas trabajo como si quieres documentar tu aprendizaje.

Estructura de cada repositorio

Cada proyecto debería tener:

  • README claro: Qué hace, cómo ejecutarlo, qué tecnologías usa. No un README de tres párrafos: uno de diez líneas con instrucciones concretas.
  • Makefile o Taskfile: Comandos para build, test, lint, run. Que cualquiera pueda clonar y ejecutar en menos de un minuto.
  • Tests reales: No tests de mentira que comprueban que 1+1 == 2. Tests que validan comportamiento, edge cases, errores esperados.
  • Docker (cuando aplique): Un Dockerfile multi-stage que produzca una imagen limpia. Un docker-compose.yml si el proyecto necesita bases de datos u otros servicios.
  • CI configurado: Un workflow de GitHub Actions que ejecute tests y linting en cada push. Es una línea en tu repo que dice “me tomo esto en serio”.

Lo que demuestra cada proyecto

ProyectoDemuestra
CLIDominio del lenguaje base, manejo de errores, testing
API RESTArquitectura web, base de datos, middleware, testing HTTP
WorkerConcurrencia, patterns de producción, graceful shutdown
Kafka consumerSistemas distribuidos, event-driven architecture
CSV a JSONI/O eficiente, streaming, composición de interfaces
Scraper (bonus)Concurrencia avanzada, resiliencia, rate limiting

No necesitas los seis. Tres proyectos bien hechos ya cuentan una historia coherente. Pero si haces los cinco principales, tienes un portfolio que cubre prácticamente todo lo que un equipo busca en un desarrollador Go.


Progresión: en qué orden construirlos

El orden importa. Cada proyecto asume que ya dominás lo que aprendiste en el anterior.

Nivel 1: CLI

Es tu primer contacto real con Go. Aquí aprendes el lenguaje: tipos, control de flujo, error handling, paquetes, compilación. Sin distracciones externas.

Tiempo estimado: 1-2 días si ya programas en otro lenguaje.

Nivel 2: API REST

Subida de complejidad. Ahora tienes HTTP, JSON, base de datos. Aprendes cómo Go estructura aplicaciones web y cómo se testean.

Tiempo estimado: 3-5 días. Más si incluyes PostgreSQL y Docker.

Nivel 3: Worker

El salto a concurrencia real. Goroutines, channels, context, wait groups. Aquí es donde Go deja de parecerse a cualquier otro lenguaje y empiezas a pensar de forma diferente.

Tiempo estimado: 2-3 días.

Nivel 4: Kafka consumer

Sistemas distribuidos. Complejidad operacional. Este proyecto no es solo código: es entender cómo funcionan las piezas a nivel de infraestructura.

Tiempo estimado: 3-5 días, incluyendo levantar Kafka en local con Docker.

Nivel 5: CSV a JSON

Vuelves a un problema aparentemente simple, pero lo atacas con todo lo que has aprendido. Streaming, interfaces, testing robusto, manejo de edge cases.

Tiempo estimado: 1-2 días para la versión básica. Más si añades concurrencia o soporte para ficheros enormes.

El roadmap completo

CLI → API REST → Worker → Kafka Consumer → CSV/JSON Converter
 │       │          │           │                │
 │       │          │           │                └─ I/O, streaming, interfaces
 │       │          │           └─ Sistemas distribuidos, event-driven
 │       │          └─ Concurrencia, goroutines, channels
 │       └─ HTTP, JSON, DB, middleware, testing
 └─ Fundamentos: tipos, errores, paquetes, compilación

Si quieres un mapa más amplio de todo el ecosistema de Go, incluyendo conceptos intermedios y avanzados, lo detallo en la guía general: Aprender Go en 2026.


Errores comunes al aprender Go con proyectos

Antes de que empieces, algunos errores que he visto (y cometido):

Empezar demasiado grande

No hagas un “microservicio completo con Kafka, Redis, PostgreSQL y gRPC” como primer proyecto. Vas a abandonar al tercer día. La CLI es tu primer proyecto por algo: es pequeño, terminable y te da confianza.

No escribir tests desde el principio

En Go, testear es trivial. El paquete testing viene incluido, go test ./... ejecuta todo, y la convención de _test.go es tan natural que no hay excusa. Si no testeas tus proyectos de aprendizaje, estás dejando sobre la mesa una de las mejores herramientas del lenguaje.

Copiar sin entender

Los LLMs te generan código Go correcto en segundos. Pero si copias sin entender por qué se usa defer aquí, por qué el error se comprueba allá, por qué el channel es buffered en este caso y no en otro, no estás aprendiendo. Usa la IA como acelerador, no como sustituto.

Ignorar el tooling

go fmt, go vet, golangci-lint. Úsalos desde el primer proyecto. No después. El tooling de Go es parte de la cultura del lenguaje y te ahorra discusiones sobre estilo que en otros lenguajes consumen horas.

No leer código de otros

Después de cada proyecto, busca implementaciones similares en GitHub. Mira cómo lo hacen otros. El código Go idiomático tiene un estilo reconocible, y comparar tu solución con otras es la forma más rápida de mejorar.


Construir es la única forma de aprender de verdad

Go no se aprende leyendo. Se aprende construyendo. Y no cualquier cosa: proyectos que te fuercen a resolver problemas reales con las herramientas que el lenguaje te da.

Los cinco proyectos que he propuesto van desde una CLI en Go para asentar los fundamentos sin distracciones, pasando por una API REST con Go que te mete de lleno en desarrollo web con base de datos, hasta un worker en Go donde la concurrencia con goroutines y channels deja de ser teoría. Kafka con Go te lleva a sistemas distribuidos y event-driven architecture, y el conversor CSV a JSON en Go te obliga a trabajar con I/O eficiente, streaming e interfaces. Y como bonus, el scraper en Go para concurrencia avanzada y patrones de resiliencia.

No necesitas seguir el orden al pie de la letra, pero te recomiendo no saltarte los primeros dos. La CLI te da los fundamentos y la API te da el contexto web. A partir de ahí, puedes ir al worker, a Kafka o al conversor segun lo que mas te interese o lo que necesites para tu trabajo. Lo que si necesitas es empezar. Abre tu terminal, ejecuta go mod init y escribe el primer main.go. El mejor momento fue hace una semana. El segundo mejor momento es ahora.

OshyTech

Ingeniería backend y de datos orientada a sistemas escalables, automatización e IA.

Navegación

Copyright 2026 OshyTech. Todos los derechos reservados