Have you ever looked at a classmate’s or colleague’s GitHub and realised you’re building almost the same golang projects? You’d be surprised to know how often this happens. A URL shortener, a chat app, a to-do list are great ways to practice Go, but when several candidates have the same projects, the project name alone does little to show what you can actually build.
That doesn’t mean you need increasingly unusual golang project ideas. You just need the kind of golang projects that give you something concrete to talk about. The 12 go projects below are laid out as practical specs, with what to build, why Go fits, the packages to consider, realistic build times, and what an interviewer can learn from the result.
If you’re still working through Go fundamentals, then you can start with the complete Golang roadmap.
What Golang Is Actually Used For (and Why It Changes What You Should Build)
If you’re choosing golang projects for your portfolio, you should always start by asking yourself one question: “Does this project really require Go to build it?” Go is widely used for API services, command-line tools, and cloud infrastructure. So, when you keep these use cases in mind while choosing a project, you have more opportunities to show what Go is genuinely good at and where it is best used.
If your project would be just as natural to build in Python or Java, it is not really a Go project; it is a project that happens to compile with go build. So, you should look for projects where Go can give you something meaningful to work with, whether that is concurrent I/O, network services, throughput, simple deployment, or systems-level control.
That is also why Go is mostly not the preferred choice for data science, ML, heavy UI development, or quick CRUD prototypes. If you’re coming from Java or Python, consider Go only when you want to work on concurrent network services, infrastructure, or tools with simple deployment. Java has a broader enterprise ecosystem, while Python is used for data and rapid development. You can also look at how Go compares with other programming languages for jobs before deciding where to focus.
You can also read about the best programming languages to learn for jobs if you want to understand the broader hiring aspect.
Transform Your Career
Choose from our industry-leading programs designed for career success
Modern Software and AI Engineering Program
Master full-stack development with AI integration
+1000 more
Modern Data Science and ML with specialisation in AI
Advanced data science techniques with AI specialization
+1000 more
Advanced AIML with Specialisation in Agentic AI
Deep dive into AIML with focus on Agentic systems
+1000 more
DevOps, Cloud & AI Platform Engineering
Build and manage AI-powered cloud infrastructure
+1000 more
AI Engineering Advanced Certification by IIT-Roorkee
Premier AI engineering certification from IIT-Roorkee
How to Use This List (Tiers, Time, and How Many You Actually Need)
We’ve divided the list into three tiers based on the depth of Go involved:
- Tier 1: Foundations: Use Go’s standard library to build complete applications. Plan for 1-2 weeks per project.
- Tier 2: Concurrency: Work with goroutines, channels, cancellation, synchronization, and concurrent I/O. Plan for 2-3 weeks per project.
- Tier 3: Systems & Infra: Work on networking, distributed components, performance, or infrastructure. Plan for 3-5 weeks per project.
The timelines assume 8-10 focused hours a week alongside a job. You can pick one project from each tier and take each through testing, error handling, logging, deployment, and the other production details covered later in the article. Three finished projects are enough to demonstrate a range of Go skills; you don’t need to complete the entire list.
You’ll also find golang projects with source code online. Use existing implementations when you get stuck or want to understand another approach, but don’t copy them into your repository. Use existing implementations when you need to understand an approach or get past a blocker, but don’t copy them into your repository. You must work on the implementation yourself so you can explain the decisions, change the code, and answer questions about it in an interview.
Tier 1: Foundation Projects (Golang Projects for Beginners)
The first four golang projects for beginners that we have covered here focus on the parts of Go you’ll use in everyday backend and CLI development. You’ll work with the standard library, HTTP, files, APIs, and basic data handling while building projects that can be completed without jumping straight into distributed systems or advanced concurrency. These beginner Golang projects can help you get started if you already know the basics of Go and want to turn them into working applications. Each one also leaves room to add testing, error handling, logging, and other production practices as you build it.
1. A CLI Task Manager with Persistent Storage
Build a todo add / list / done / rm command-line tool with subcommands, flags, and either JSON or SQLite persistence.
Go is a good fit here because: CLI tools are one of Go’s common use cases, particularly when you want to compile the application into a single binary with no runtime dependencies. You can even cross-compile it, such as using GOOS=darwin go build to create a macOS binary from a Linux machine.
Difficulty: Beginner
Key packages: flag, encoding/json, os, errors; use spf13/cobra for richer subcommands or mattn/go-sqlite3 for SQLite persistence.
Build time: 1 week
What it demonstrates: Organising a Go module with cmd/ and internal/, handling and wrapping errors instead of relying on panic, and building a binary that someone else can run.
We’re keeping this one to-do app in the list because the focus here is to have the chance to build a CLI in Go and see how a Go application can be compiled into a single binary that others can run.
2. A URL Shortener REST API
Build a small URL-shortening service with POST /shorten generating a Base62 code and GET /{code} returning a 302 redirect. Start with an in-memory store, then move the data to Redis or Postgres and add hit counters.
Go is a good fit here because: the in-memory store introduces concurrent access. Multiple HTTP requests can read and write the same map at the same time, so you’ll need to protect it with sync.RWMutex. Run go test -race to catch unsafe access. This is also one of those golang projects for beginners where you can understand Go’s approach to sharing state between goroutines.
A simple mutex-guarded store could look like this; you can use this for your :
type Store struct {
mu sync.RWMutex
data map[string]string
}
func (s *Store) Get(key string) (string, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
value, ok := s.data[key]
return value, ok
}
Here, RLock() allows multiple reads at the same time while preventing a write from happening concurrently. You can then use the same pattern for methods that modify the map with Lock().
Difficulty: Beginner – Intermediate
Key packages: net/http, go-chi/chi or gin-gonic/gin, sync, encoding/json, redis/go-redis
Build time: 1 – 1.5 weeks.
What it demonstrates: HTTP handlers and middleware, appropriate status codes, concurrent-safe shared state, and the difference between a regular Go map and one that can safely be accessed by multiple goroutines.
For the HTTP layer, you can use either Gin or Chi. Both are worth trying, but the standard library’s net/http is enough to build the core API too.
3. A Public-API CLI Client with Caching and Timeouts
Build a CLI that queries a public API, such as weather, currency, train, or cricket-score data. Start with the API request itself, then add local disk caching, retries with exponential backoff, and a hard timeout.
Go is a good fit here because: You can use context.Context here. Every outbound request can carry a deadline, and cancelling the CLI with Ctrl-C can stop work that is still in progress instead of leaving the request running.
Difficulty: Beginner – Intermediate
Key packages: net/http, context, time, encoding/json, os
Build time: 1 week
What it demonstrates: making HTTP requests from Go, handling timeouts and cancellation, retrying failed requests, and deciding when cached data can be used instead of making another API call.
In some of the beginner golang projects, when you make an API request, you don’t always know how long the server will take to respond. context.Context lets you set a deadline for that request and cancel it when the user stops the CLI. This means your program can stop waiting for work that is no longer useful instead of leaving the request running in the background.
4. A Static Site Generator (Markdown to HTML)
Build a small static site generator that reads a content directory, parses Markdown and front matter, renders the content through templates, and generates the final HTML files. Add an index page and tag pages so you have to think about how content moves through the whole pipeline.
Go is a good fit here because: you get to work with parts of the standard library that are useful beyond this project, particularly html/template, io/fs, and the io.Reader/io.Writer model. It’s also a good place to use interfaces for a real design decision. For example, separating the content reader from the renderer.
Difficulty: Intermediate
Key packages: html/template, io/fs, path/filepath, yuin/goldmark
Build time: 1 – 2 weeks
What it demonstrates: Working with Go’s standard library instead of depending on a framework for every part of the application, handling files and templates, and using interfaces to separate different parts of the implementation.
Check whichever idea seems most interesting to you and give your all to turn them into your best golang projects.
If you’re building toward backend development, these foundation projects also give you useful groundwork for a broader backend developer roadmap.
Scaler Placement Report and Statistics
Scaler learners achieved 2.5x salary growth with average post-Scaler CTC reaching ₹23L.
Tier 2: Go Projects That Use Concurrency
Some applications need to deal with many pieces of work at the same time. A scraper might fetch hundreds of URLs. A file processor might handle thousands of files. A server might receive many requests while background jobs are still running. This is where golang concurrency features are used.
The four golang projects in this tier give you those kinds of problems to solve. You’ll use goroutines to run work concurrently, channels to coordinate that work, and cancellation to stop it when it is no longer needed.
There’s also an important part of writing concurrent Go code: you need to control how much work runs at once. Starting a goroutine for every task may work for a small test, but it can overwhelm the system when the workload grows. The golang project ideas below give you opportunities to set those limits and see why they matter.
5. A Concurrent Web Scraper with a Bounded Worker Pool
Build a crawler that starts with a set of seed URLs, fetches pages concurrently, extracts links, and keeps track of URLs it has already visited. Give it a fixed number of workers so you can control how many requests run at once. Add robots.txt checks, per-host rate limits, and structured output as you extend it.
Go is a good fit here because: A web scraper needs to fetch many URLs without letting the number of requests grow without limit. You can use a worker pool to process URLs, a buffered channel as a semaphore to limit in-flight requests, sync.WaitGroup to track completed work, and a mutex to protect the visited-URL set. Use context cancellation to stop the crawl when it needs to end.
Difficulty: Intermediate
Key packages: net/http, sync, context, golang.org/x/sync/semaphore, PuerkitoBio/goquery or gocolly/colly
Build time: 2 weeks
What it demonstrates: controlling concurrent work instead of creating unlimited goroutines, coordinating workers, protecting shared state, and handling failures without leaving work running in the background.
You can test it by deliberately giving the scraper more URLs than it can process at once. You should be able to see that the worker limit actually controls the number of concurrent requests rather than simply creating a goroutine for every URL.
Also, keep the robots.txt and per-host rate-limit checks. They make the scraper behave more like a tool you could actually run against public sites, rather than just a concurrency exercise.
6. A Rate Limiter You Can Drop Into Any HTTP Service
Build a rate limiter as net/http middleware and support both token-bucket and sliding-window approaches. Start with per-IP limits, then add per-API-key limits and a Redis-backed version that can work across multiple service instances.
Go is a good fit here because: rate limiting makes you deal with shared state and timing while requests are arriving concurrently. You’ll work with time, select, and mutexes in the in-process version. Then, when you move the state to Redis, you’ll see why a limiter that works on one server cannot simply be copied across three replicas behind a load balancer.
Difficulty: Intermediate
Key packages: golang.org/x/time/rate, sync, time, net/http, redis/go-redis
Build time: 2 weeks
What it demonstrates: concurrency in golang state management, HTTP middleware, rate-limiting algorithms, and the difference between a limiter that works on one instance and one that has to coordinate across multiple instances. Rate limiting also comes up regularly in system-design interviews, so having implemented one gives you something concrete to discuss alongside a system design roadmap.
Here’s how you can compare the algorithms by looking at how they handle bursts and how much state they need:
| Algorithm | Burst behaviour | Memory cost | When to use |
| Token bucket | Allows controlled bursts | 1 key (2 fields) | Bursty traffic with average-rate limits |
| Leaky bucket | No bursts; steady drain | 1 key (1 - 2 fields) | Policing or shaping traffic |
| Fixed window | Allows up to 2× burst at boundaries | 1 key | Simple API limits |
| Sliding window | No boundary bursts | O(n) entries | When exact request tracking matters |
A key is a Redis entry used to store the limiter's state for a client. “2 fields” means that one key contains two pieces of state. O(n) entries means the memory grows with the number of requests being tracked in the window, so a busy client requires more storage
7. A Concurrent File Processing Pipeline
Build a batch processor for a task such as thumbnail generation, log parsing, or CSV-to-database ingestion. Break the work into separate stages and connect those stages with channels. If one stage encounters an error, cancel the rest of the pipeline instead of allowing the other stages to keep processing.
Go is a good fit here because: the pipeline gives you a practical way to work with channels and the fan-out/fan-in pattern. You can run several workers for a stage, combine their results in the next stage, and use errgroup with context to cancel the pipeline when one of those workers fails.
Difficulty: Intermediate
Key packages: golang.org/x/sync/errgroup, context, image or encoding/csv, bufio, sync
Build time: 2 weeks
What it demonstrates: composing several concurrent stages, coordinating workers, handling cancellation, and managing backpressure so that one stage does not keep producing data faster than the next stage can process it.
8. A Background Job Queue with Retries and a Dead-Letter Queue
Build a job queue that stores jobs in Redis or Postgres and has a pool of workers processing them. Add retries with exponential backoff for failed jobs, move jobs that keep failing to a dead-letter queue (DLQ), and make sure SIGTERM lets workers finish in-flight jobs before the service exits.
Go is a good fit here because you have several pieces of backend behaviour to handle together: a worker pool for processing jobs, context for cancellation, retries for temporary failures, and graceful shutdown when the service is stopped. You’ll also need to think about at-least-once delivery, where the same job may be processed more than once.
Difficulty: Intermediate - Advanced
Key packages: hibiken/asynq or go-redis, context, os/signal, sync, log/slog
Build time: 2.5 - 3 weeks.
What it demonstrates: how you handle failures in a background service. You’ll need to decide when a job should be retried, what happens to a job that keeps failing, how to make repeated processing safe through idempotency, and how to shut down without dropping work.
Build the worker pool yourself first, so you understand what happens when jobs are added, picked up, retried, and completed. Then try the same setup with asynq and compare the two implementations. Look at which parts asynq takes care of, such as worker management, retries, and job state, and which decisions still belong to your application. This will give you a better understanding of the library.
Scaler Alumni and Their Success Stories
Tier 3: Systems and Infrastructure Projects (Advanced Golang Projects)
The first two tiers covered Go fundamentals and concurrency in golang. Here, the projects move into systems and infrastructure work: networking, storage, processes, containers, and resource management.
The problems are a bit different here. You’ll need to think about how the system uses CPU and memory, how processes communicate, how data is stored, and what happens when a component stops responding. These are the kinds of concerns that come up in infrastructure and platform work. So, get ready to now work on these golang project ideas!
9. An In-Memory Key-Value Store with TTL and Persistence (a Mini Redis)
Build a small key-value store that supports GET, SET, DEL, and EXPIRE over a TCP connection. Use a simplified RESP protocol for communication, split the in-memory data across shards to reduce lock contention, and run a background goroutine to remove expired keys. Add append-only-file persistence so the store can replay its data after a restart.
Go is a good fit here because: you can work directly with TCP connections using net.Conn, with one goroutine handling each connection. The data store also gives you a real choice between sync.Map and a sharded map protected by RWMutex. Instead of deciding based on theory, benchmark both approaches with go test -bench.
Difficulty: Advanced
Key packages: net, bufio, sync, time, encoding/binary, testing
Build time: 3 - 4 weeks
What it demonstrates: choosing and evaluating concurrent data structures, working with TCP connections, handling expiry and persistence, and using benchmarks to support an engineering decision. Include the benchmark results in the README so the reader can see why you chose one implementation over the other.
10. An HTTP Load Balancer with Health Checks
Build a reverse proxy that sits in front of several backend servers and distributes requests between them. Start with round-robin routing, then add least-connections routing, background health checks, and atomic request counters. A backend that stops responding should be removed from the pool and added back once it becomes healthy again.
Go is a good fit here because: httputil.ReverseProxy handles the basic proxying, so you can spend your time on the routing logic and backend management. The interesting part is keeping the backend pool updated while requests are being routed through it. Health checks run in the background, while incoming requests need to see a consistent view of which backends are available.
Difficulty: Advanced
Key packages: net/http/httputil, sync/atomic, time, context, net/http
Build time: 3 weeks
What it demonstrates: reverse-proxy development, load-balancing strategies, health checks, concurrent state management, and atomic operations. It also gives you a practical way to understand what happens between a client request and the backend service handling it.
11. A Real-Time Chat Server over WebSockets
Build a multi-room chat server where clients connect over WebSockets and can join rooms, send messages, and see who is online. Use a central hub to manage connected clients, separate read and write goroutines for each client, and channels to broadcast messages and handle disconnects.
Go is a good fit here because: you can keep ownership of the connected-client registry in a single hub goroutine instead of having several goroutines access the same map. Other parts of the server communicate with the hub through channels. This gives you a practical example of Go’s approach to managing shared state without putting a mutex around every operation.
Difficulty: Advanced
Key packages: gorilla/websocket or coder/websocket, sync, context, encoding/json
Build time: 2.5 - 3 weeks.
What it demonstrates: designing a concurrent server, managing long-lived connections, coordinating goroutines through channels, and handling clients that disconnect or stop consuming messages.
There is one case you should account for in the design: what happens when one client is too slow to receive a broadcast? Give each client a buffered send channel so a slow connection does not hold up the entire broadcast. If that buffer fills up, you can drop messages or disconnect the client, depending on the behaviour you want from the application.
12. A gRPC Microservice Pair with Observability
Build two services that communicate over gRPC using Protocol Buffers. For example, an order service can call an inventory service. Add interceptors for logging and authentication, propagate deadlines between the services, and add structured logs plus Prometheus metrics or OpenTelemetry traces. Finish with a docker compose up setup that starts both services.
Go is a good fit here because: gRPC and Protocol Buffers are widely used with Go, and the project lets you work through problems that appear when services communicate with each other. In particular, you’ll see why context deadlines need to travel across service boundaries. If the inventory service takes too long to respond, the order service should not keep waiting after its own deadline has expired.
Difficulty: Advanced
Key packages: google.golang.org/grpc, protoc-gen-go, grpc-ecosystem/go-grpc-middleware, log/slog, go.opentelemetry.io/otel
Build time: 3 - 4 weeks
What it demonstrates: building and operating a service rather than only writing its business logic. You’ll have to deal with service-to-service communication, deadlines, authentication, logs, metrics, traces, and local deployment.
If you want to take the infrastructure side further, a natural next project is a small Kubernetes controller or a kubectl plugin using client-go. You can continue with this Kubernetes roadmap.
The Production-Ready Checklist: What Actually Separates a Portfolio Repo from a Tutorial Repo
In all honesty, you can find versions of almost every go projects above on GitHub, so building the basic version alone might not tell someone much about how you work.
So, before adding another project, take one of your existing ones and go through this checklist below. These are small additions individually, but together they show that you understand what it takes to run and maintain Go code and a good golang project structure.
| Practice | What it Shows | How to add it to any project on this list |
| Wrapped, typed errors | Good error handling keeps the original cause available when something fails. | Return errors instead of panicking outside main. Wrap them with fmt.Errorf("fetching user %d: %w", id, err). Define sentinel errors such as ErrNotFound and check them with errors.Is / errors.As. |
| context.Context propagation | A request that waits indefinitely can hold resources and keep dependent work running. | Pass ctx context.Context as the first parameter to functions that perform I/O. Set deadlines on outbound HTTP and database calls. Don’t store contexts in structs. |
| Graceful shutdown | A service should be able to stop without dropping requests or background work that is already in progress. | Use signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) and call srv.Shutdown(ctx) with a timeout. For workers, stop accepting new jobs, finish in-flight work, then exit. |
| Structured logging | Structured logs let you search and filter events when a service is handling many requests. | Use log/slog and log key-value pairs such as request IDs, user IDs, and errors. Log important events at the application boundaries instead of adding logs to every function. |
| Externalised config | Ports, credentials, and environment-specific settings should not be embedded in your source code. | Use environment variables with flag overrides. Add a .env.example, never commit .env, and fail clearly when required configuration is missing. |
| Table-driven tests + -race | Table-driven tests are idiomatic Go, while the race detector can catch unsafe concurrent access that ordinary tests may miss. | Define test cases as []struct{...} and run each with t.Run(tc.name, ...). Run go test -race ./... in CI. Focus coverage on important behaviour rather than chasing 100%. |
| Standard project layout | A familiar structure makes a Go repository easier for another developer to navigate. | Keep entry points in cmd/<binary>/main.go, private application packages in internal/, and main thin. Don’t add a large directory structure just because you found a “standard Go layout” online. |
| Multi-stage Dockerfile | A smaller runtime image reduces the amount of software shipped with your application. | Compile in a golang:1.x build stage and copy the binary into a gcr.io/distroless/static or scratch image. Use CGO_ENABLED=0, run as non-root, and add a health check where appropriate. |
| CI pipeline | Your code should build and pass its tests on a clean machine, not only on your laptop. | Use GitHub Actions to run go vet, golangci-lint, go test -race ./..., and go build on every push. |
| A real README | Someone reviewing your repository needs to understand the project before they start reading the code. | Explain what it does, why you built it, how to run it, and include an architecture diagram. Add a design decisions & trade-offs section so you can explain why you chose one approach over another. |
| Health & readiness endpoints | These endpoints let you distinguish between a process that is running and a service that is actually ready to receive traffic. | Add /healthz for process health and /readyz for dependency readiness. |
| Makefile or just file | A simple command to run, test, lint, or build the project removes unnecessary setup for anyone reviewing it. | Add commands such as make run, make test, make lint, and make docker. |
You’ll be able to understand Graceful shutdown when you can see the sequence: stop accepting new work, give existing requests time to finish, then exit.
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
srv := &http.Server{Addr: ":8080"}
go func() {
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(shutdownCtx)
}()
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
For go projects with concurrent code, also make the tests exercise the cases where goroutines interact with each other. A small table-driven test can keep those cases easy to add and compare:
tests := []struct {
name string
in string
want string
}{
{"existing key", "name", "Go"},
{"missing key", "unknown", ""},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := store.Get(tc.in)
if got != tc.want {
t.Errorf("got %q, want %q", got, tc.want)
}
})
}
Run the concurrent tests with:
go test -race ./...
For containerisation, a multi-stage build keeps the Go toolchain out of the final image. The first stage compiles the application; the second contains only what is needed to run it.
FROM golang:1.24 AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server ./cmd/server
FROM gcr.io/distroless/static
COPY --from=build /app/server /server
ENTRYPOINT ["/server"]
For the multi-stage Dockerfile row, if you’re not familiar with multi-stage builds yet, you can start with these containerisation fundamentals before applying it to your project.
You don’t need to apply this checklist to every repository you have. Take the project that you think you’ve given your best and spend a weekend bringing it through all twelve areas. Then pin that repository to your GitHub profile.
These practices also carry over to the wider skill set backend teams hire for, so the work you put into one Go project does not stay limited to Go.
The Concurrency Patterns Behind These Golang Projects
As you build these projects, you’ll run into the same kinds of golang concurrency problems repeatedly: too many goroutines doing the same work, several stages that need to run at the same time, shared state that needs protection, or work that needs to stop when its caller is cancelled.
Go has established patterns for handling each of these problems. The table below connects those patterns to the projects in this guide, so you can see what problem each one solves and where you can practise it.
| Pattern | What problem it solves | Which project uses it |
| Worker pool | Limits the number of goroutines working at once so you don’t overwhelm memory, file descriptors, or the service you’re calling. | 5 Web Scraper, 8 Job Queue |
| Fan-out / fan-in | Sends work to multiple goroutines and brings their results back together. | 7 Processing Pipeline |
| Pipeline (staged channels) | Moves data through separate stages without loading the entire dataset into memory at once. Each stage can work concurrently. | 7 Processing Pipeline |
| Semaphore (buffered channel or x/sync/semaphore) | Limits access to a particular resource, such as connections, API requests, or disk I/O, separately from the number of workers. | 5 Web Scraper, 10 Load Balancer |
| Context cancellation & deadlines | Stops work when the request that started it has been cancelled, or its deadline has passed. | 3 API Client, 8 Job Queue, 12 gRPC Services |
| select + time. Ticker/time.After | Handles timeouts, repeated tasks, and multiple channels without waiting forever on one of them. | 6 Rate Limiter, 10 Load Balancer |
| Mutex vs channel | A mutex protects shared data; a channel can be used when goroutines need to pass work or ownership between each other. | 2 URL Shortener, 11 Chat Server |
| errgroup | Runs related goroutines together and cancels the remaining work when one returns an error. | 7 Processing Pipeline |
| Single-owner goroutine (hub) | Gives one goroutine ownership of shared state so other goroutines communicate with it through channels instead of locking the state directly. | 11 Chat Server |
| Graceful shutdown | Lets in-flight work finish before a service exits after receiving SIGTERM. | 2 URL Shortener, 8 Job Queue, 11 Chat Server |
| sync/atomic | Updates simple counters and flags safely without taking a mutex, which can matter on frequently accessed paths. | 10 Load Balancer |
One thing to watch for: goroutine leaks
Every goroutine you start needs a way to stop. A goroutine that keeps waiting on a channel, timer, network operation, or other work after nobody needs its result is a goroutine leak.
When testing concurrent code, go test -race ./... can catch unsafe memory access, while checking runtime.NumGoroutine() before and after a test can help spot goroutines that were left running. Neither catches every possible leak, but both are useful checks when you’re testing concurrent code.
You can take the example of a worker because it shows the main idea behind bounded concurrency without adding much code:
jobs := make(chan Job)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
process(job)
}
}()
}
for _, job := range jobsToProcess {
jobs <- job
}
close(jobs)
wg.Wait()
Here, only five workers can process jobs at the same time. The jobs channel provides the work queue, WaitGroup lets the main goroutine wait for all workers to finish, and closing the channel tells the workers that no more jobs are coming.
Where Go Is Actually Hired For in India
Go is used across Indian engineering teams, but its presence is more concentrated than Java, Python, JavaScript, and several other widely used languages. When you look at Golang jobs, you’ll be able to find more opportunities in areas like infrastructure, backend systems, developer tooling, and services operating at scale. Let’s look at the areas where you can find Golang developer jobs and what the work usually involves.
Infrastructure, DevTools and Platform Engineering
If you look at where Go is used, infrastructure is one of the first areas you’ll come across. Kubernetes, Docker, and Terraform are prominent examples from the Go ecosystem, and the language is widely used for cloud and developer tooling.
The 2025 Go Developer Survey found that 91% of developers are satisfied with Go. CLI applications and API services were the most common use cases, with 55% of respondents saying they build both.
So when you search for Go roles, don't limit yourself to titles that say Golang Developer. Look for platform engineering, cloud infrastructure, developer tools, backend infrastructure, and SRE-related roles as well.
Backend Services and Distributed Systems
You can also find Go in regular backend engineering, particularly when the service involves a lot of network communication, concurrent work, or communication between multiple services.
That doesn't mean every high-scale backend is written in Go. Java, Kotlin, C++, Python, and other languages are widely used for the same kinds of systems. The point is that Go tends to appear more often when the backend work has a strong systems or infrastructure component.
The survey also shows that 81% of respondents had more professional development experience than Go-specific experience, and more than 80% reported learning Go after they had already started their professional careers.
If you're learning Go now, you therefore don't need to think of it as a language that has to replace everything else you know. Your existing backend experience can be what makes the Go skill relevant.
Fintech and Payments
You can also find Go in fintech and payment engineering, particularly around services that handle large numbers of requests or transactions.
Go isn't the default language for fintech in India. Java, Kotlin, C++, Python, and other languages have a major presence too. But if you're looking at Golang developer roles in this sector, you'll often find the language attached to backend services, transaction systems, infrastructure, or other high-throughput workloads.
Consumer-Scale Products
Go also appears in consumer products where a service has to handle many concurrent connections or requests. Streaming, commerce, social products, and gaming can all have this kind of workload. If you look at a service such as a chat system, for example, thousands of users may be connected at the same time, and the server needs to keep those connections active without creating a heavy OS thread for every user. When you come across a Go role for this kind of service, you’ll likely be working with keeping connections alive, coordinating work between them, and making sure the service continues to respond as the number of users grows.
What Should You Expect From the Go Job Market?
Now, when the job market is in question, for golang jobs India has openings that are actually a bit harder to find than other popular languages. But you can also find Go in roles with a fairly specific technical focus.
And this also means that your experience and their requirements here would count a lot. If you're searching for your first job, you may find more entry-level options by keeping your search broader across backend development, and a golang internship can also be one route into the language if you find a team willing to take on someone early in their career. As you gain experience, you can narrow your search to teams using Go for infrastructure, distributed systems, platform engineering, or high-concurrency backend services. As you gain experience, you can look specifically for teams using Go for infrastructure, distributed systems, platform engineering, or high-concurrency backend services.
Also, in terms of golang developer salary, the average pay according to Indeed is ₹8,30,000+ LPA in Maharashtra. Keep in mind that salaries vary depending on the company and location.
If you want to understand more about the differences in salaries, then you can look at how backend pay scales with experience in India.
And if you're wondering why so many Go openings ask for prior experience, look at SDE-1 vs SDE-2 vs SDE-3 expectations. It’ll give you a better idea of how the responsibilities change as you move into the kinds of roles where Go is usually required.
If you're starting out, you don't need to choose Go over every other backend language just yet. Build your backend fundamentals first. Once you have them, Go can give you a path into infrastructure, platform engineering, and distributed-systems roles.
How to present a Go project on your resume and GitHub
It’s confusing, right? Your golang projects for resume need to be short, but these projects can cover a page full of description. Worry not; your one-line description can completely work because it’s the repository where you show the technical work done.
If you built the web scraper, for example, record the things you actually tested while building it:
- the number of workers
- requests per second or pages processed
- what happened when you increased the worker count
- how you handled a slow or failed request
- whether go test -race found anything
- how you stopped the workers when the crawl ended
If you benchmarked the project, put the command and result in the README. Go's benchmarking support gives you a standard way to measure this, and the output can report values such as ns/op.
For concurrent projects, run:
go test -race ./...
golang projects such as the URL shortener, scraper, job queue, and chat server have multiple goroutines accessing shared data, so run go test -race ./... as part of your tests. A passing race-detector run does not mean the code has no data races. It only reports races that occur while the tests are running, so the tests need to exercise the concurrent operations in your code.
Do the same with design decisions. If you change the worker count after a benchmark, keep both the old and new result. If you moved from an in-memory queue to Redis, explain what problem that solved. If you replaced a single mutex with sharded state, show the benchmark that made you change it.
That gives you material for the resume too.
Instead of: Built a web scraper in Golang.
You can write: Concurrent crawler processing 500 pages/min with a bounded 20-worker pool and tested with go test -race.
Only use the 500 pages/min if you have measured it.
For golang projects github, you don't need to worry about overcrowding your space. GitHub currently lets you pin repositories on your profile, and its own guidance recommends using pinned projects to direct attention to selected work and add your best golang projects for the interviewers to check.
The follow-up golang interview questions each project invites
Now take the golang project you have actually built and try to break your own design.
Web scraper
- What happens if 20 workers become 100?
- At what point does adding workers stop improving throughput?
- What happens when one request hangs?
- How does cancellation reach every worker?
- How are duplicate URLs prevented?
Rate limiter
- What happens when the service runs on three machines?
- Where is the rate-limit state stored?
- What happens when one instance restarts?
- Why did you choose a token bucket or sliding window?
Job queue
- What happens if a worker dies halfway through a job?
- Can the same job be processed twice?
- How does the consumer handle that?
- When does a failed job enter the dead-letter queue?
Chat server
- What happens when one client stops reading?
- Can that client hold up everyone else?
- Who owns the client registry?
- What happens to connected clients during shutdown?
Key-value store
- Why did you choose a sharded map or sync.Map?
- What did the benchmark show?
- How does TTL expiry happen?
- What happens when the process restarts?
gRPC services
- What happens when the caller's deadline expires?
- Does the downstream request stop as well?
- How do you return the downstream failure?
- What happens when the inventory service is unavailable?
All these questions together might look scary at first, but the best way to deal with them is to treat them as a testing checklist. So, you don’t have to prepare individual answers; you'll just check them and know!
So don’t shy away from doing this: Increase the worker count. Kill a worker. Stop Redis. Connect a client that doesn't read. Let a request hit its deadline. Run the benchmark again.
Then put the interesting results in the README.
If you’re also working on the wider structure of your portfolio, see how other engineers structure a job-ready project portfolio.
Conclusion
Go gives you plenty of room to build interesting backend systems. Start with golang projects that make you work with concurrency, then take it further: handle failures, control how work is scheduled, shut the service down properly, test the race-prone parts, and make the whole thing runnable outside your laptop. You don't need to build all twelve projects to learn this. Pick one Tier 2 project this week, take it through the production-ready checklist, and then decide what you want to build next.
If you want to develop these backend skills through hands-on projects with mentorship, you can explore Scaler Academy.
Also Explore These Projects to Build Your Portfolio
FAQ
1. What projects should I build to learn Golang?
Start with a CLI tool or REST API to get comfortable with Go's standard library and tooling. Then move to a project where concurrency is part of the problem, such as a worker-pool web scraper, rate limiter, or job queue. This gives you experience with the parts of Go that don't come up as much in a typical CRUD API.
2. Is Golang good for beginners?
Yes. Go has a small syntax, relatively few language features, and strong tooling built into the language ecosystem. You can start using it without learning a large framework first. Though you might need more practice with concurrency, particularly once you start working with cancellation, shared state, and goroutine lifecycles.
3. What is Go actually used for?
Go is widely used for network services, APIs, command-line tools, infrastructure software, and systems where a compiled binary and predictable resource usage are useful. Docker, Kubernetes, Terraform, and Prometheus are examples of major infrastructure projects written in Go. Go is not commonly used for areas such as data science, machine learning, or frontend development.
4. How long does a Golang project take to build?
It depends on the project and how much time you can give it. A beginner CLI or API might take 1-2 weeks, while a concurrency-heavy project can take 2-3 weeks. A systems project such as a key-value store or gRPC service pair can take 3-5 weeks. These estimates assume roughly 8–10 focused hours per week.
5. Are Golang projects enough to get a job in India?
Projects are a great addition, but you do require other aspects. You need solid backend fundamentals and the ability to explain the code you have written. Go has a smaller job market in India than languages such as Java and Python, and many Go openings are aimed at developers who already have backend experience. Building your backend fundamentals first and then specialising in Go can give you a more realistic path into Go roles.
6. What should a Golang project include to look professional?
For the projects in this guide, start with wrapped errors, context propagation, graceful shutdown, structured logging with log/slog, externalised configuration, table-driven tests, and go test -race for concurrent code. Add a multi-stage Dockerfile, CI, and a README that explains how the project works, how to run it, and the important design decisions you made.
7. How should I structure a Go project?
For a small portfolio project, you can keep the structure simple. Put executable entry points under cmd/<name>/main.go, application-specific private packages under internal/, and keep main focused on wiring the application together. You don't need to reproduce a large community project layout for a small Go project.
8. Should I use Gin, Chi, Fiber, or the standard library?
Start with Go's net/http package. It gives you enough to build a lot of HTTP services and lets you understand how Go's HTTP stack works before adding another framework. Once you're comfortable with it, you can look at Chi for lightweight routing and middleware or Gin if you want more built-in functionality. The important part is understanding what the framework is doing rather than using one to avoid learning the standard library.
