Go is small on purpose, so weak candidates hide less. These questions check whether someone understands goroutines, interfaces and Go’s deliberate simplicity.
Hiring a Go developer is easy. Telling a real one from a convincing résumé is the hard part — and it’s most of what we do. These are grouped by level, because the same question that stretches a junior is a warm-up for a senior.
Junior Go interview questions
0–2 years
Syntax, types and error handling.
How does Go handle errors?
Errors are ordinary values returned alongside results and checked explicitly with if err != nil; there are no exceptions for ordinary control flow.
Wants try/catch and treats explicit checks as a flaw.
What is the difference between a slice and an array?
An array has a fixed length that is part of its type; a slice is a growable view over a backing array with length and capacity.
Uses fixed arrays everywhere, unaware of slices.
What are defer, panic and recover?
defer schedules cleanup at function return; panic/recover handle truly exceptional situations, not routine errors.
Uses panic for normal error handling.
What is a struct and how does Go do “inheritance”?
Structs group fields; Go favours composition via embedding rather than class inheritance.
Looks for class inheritance and misses embedding.
What is a pointer in Go and when do you use one?
A reference to a value’s address; used to mutate a caller’s value or avoid copying large structs. Go has no pointer arithmetic.
Cannot say when to take a pointer receiver.
What does the zero value concept mean?
Every type has a usable zero value (0, “”, nil), so variables are always initialised; good APIs make the zero value useful.
Assumes uninitialised variables are undefined.
What is a map and is it safe for concurrent use?
A hash table; plain maps are not safe for concurrent writes and need a mutex or sync.Map.
Writes to a shared map from goroutines with no synchronisation.
What is the difference between := and var?
:= declares and infers inside functions; var works at package level and when you want an explicit type or zero value.
Confused about scope rules for :=.
Mid-level Go interview questions
2–5 years
Concurrency and interfaces.
What is a goroutine and how does it differ from an OS thread?
A lightweight, runtime-scheduled function multiplexed onto OS threads, cheap enough to run thousands. They know the runtime handles scheduling.
Equates a goroutine one-to-one with an OS thread.
How do channels work?
Typed conduits for communicating between goroutines; unbuffered channels synchronise sender and receiver, buffered ones decouple up to capacity.
Uses shared memory with no synchronisation instead of channels or mutexes.
What does “share memory by communicating” mean?
Prefer passing data over channels rather than sharing mutable state behind locks, which reduces race conditions.
Never internalised the idiom.
How do interfaces work in Go?
They are satisfied implicitly by any type implementing their methods; small interfaces defined at the point of use are idiomatic.
Defines huge interfaces or expects explicit implements.
How do you avoid goroutine leaks?
Ensure every goroutine can exit — via context cancellation, closing channels, or bounded work — and don’t block forever on a channel.
Spawns goroutines that block forever with no cancellation.
What is context.Context for?
Carrying cancellation, deadlines and request-scoped values across API boundaries, so work stops when a request is cancelled.
Ignores context and can’t cancel in-flight work.
What is a race condition and how do you detect it?
Concurrent unsynchronised access to shared state; the built-in -race detector surfaces them in tests.
Never run the race detector.
When do you use a pointer vs value receiver?
Pointer receivers to mutate or avoid copying, value receivers for small immutable types; keep it consistent per type.
Mixes both arbitrarily on the same type.
Senior Go interview questions
5+ years
Performance, design and tooling.
How does Go’s garbage collector affect design?
A concurrent, low-latency collector; you reduce pressure by limiting allocations, reusing buffers (sync.Pool) and avoiding unnecessary pointers.
No awareness of allocation cost.
How do you profile and optimise a Go service?
pprof for CPU, memory and blocking profiles; benchmark with testing.B; optimise the measured hot path.
Guesses at bottlenecks without pprof.
How do you design concurrency for a high-throughput service?
Bounded worker pools, backpressure via buffered channels, context-based cancellation, and avoiding unbounded goroutine growth.
Spawns an unbounded goroutine per request.
What are common concurrency patterns in Go?
Fan-out/fan-in, worker pools, pipelines and the select loop for multiplexing channels and timeouts.
Only knows how to start a goroutine.
How do you structure a large Go project?
Clear package boundaries by responsibility, small interfaces at consumers, avoiding cyclic imports, and keeping internal for private packages.
One giant package with cyclic dependencies.
How does error wrapping work in modern Go?
fmt.Errorf with %w wraps errors, and errors.Is/errors.As inspect the chain, preserving context without losing type.
Loses the original error by formatting it into a string.
When would you reach for generics in Go?
For genuinely type-generic containers and algorithms; not as a replacement for interfaces where behaviour, not type, is what varies.
Overuses generics where a simple interface fits.
How do you handle configuration and graceful shutdown?
Load config from env/flags, and on a termination signal cancel the root context, drain in-flight work and close resources before exiting.
Kills the process without draining requests.
Build and score a full interview with our free interview scorecard tool, browse the full question hub, or see how we interview engineers.