i knew express. i was comfortable. so why did i throw myself into go, a language that made me question everything i thought i knew about backend dev? honest story.
Suprim Khatri
FullStack Developer · March 15, 2026
i had a good thing going with express. knew how to spin up a rest api, wire middleware, connect a db, handle auth. felt natural.
so when i kept feeling this pull toward go, i ignored it for a while. told myself — backend is backend, learn the concepts in one language and transfer them. that logic made me choose express over go when i was starting out. honestly, right call at the time.
but the itch never went away.
couldn't give you a perfectly rational answer. i just wanted to. sometimes that's enough.
what i knew going in:
what i didn't know: it would completely change how i think about code.
coming from js, go felt like someone took away all my toys.
no npm install something-that-does-everything. no magic abstractions. no try/catch. just you, the language, and a compiler that refuses to let anything slide.
first thing that broke my brain: pointers.
in js, you never think about memory. the runtime handles it. in go, you're suddenly writing *pgxpool.Pool and &todo.ID everywhere and asking yourself — wait, what is actually happening here?
var todo models.Todo // build the struct in memory
rows.Scan(&todo.ID) // pass the address so Scan can write into it
todos = append(todos, &todo) // store the address, not a copytook me an embarrassing amount of time to understand why you'd do var todo models.Todo instead of var todo *models.Todo.
the answer: Scan needs real memory to write into. a pointer to nothing is just an address to an empty lot — the postman shows up and there's no house.
once that clicked, something shifted.
js hides memory from you. that's a feature — it makes the language approachable. but it also means you can spend years writing js without ever understanding what's actually happening when you pass a value around.
go makes it explicit. every * or & is a deliberate decision about memory. verbose at first. then muscle memory. then you start appreciating it.
same thing happened with error handling. no try/catch in go — every function returns an error you have to deal with manually:
rows, err := pool.Query(ctx, query)
if err != nil {
return nil, fmt.Errorf("GetAllTodos: %w", err)
}felt like noise at first. then i realized — this is actually great. every error is explicit. nothing fails silently. you know exactly what can go wrong and where.
compare that to js where a promise can reject and you don't even know unless you remember to .catch() it.
won't sugarcoat this. the js ecosystem is incredible.
better auth, drizzle, zod, resend, vercel ai sdk — everything is one npm install away and works like magic.
in go, you wire things up yourself. no better auth equivalent. no drizzle. validation is manual — switch cases on struct tags or a library like go-playground/validator.
type CreateTodoRequest struct {
Title string `json:"title" validate:"required,min=1,max=255"`
Description string `json:"description" validate:"omitempty,max=1000"`
}for a while this felt like a downgrade. then i realized it was the opposite.
when you use magic libraries, you understand the what but not the why. when you build auth yourself in go — generating jwt tokens, setting httponly cookies, handling refresh logic, writing email verification flows — you understand auth at a level that using better auth never gave me.
// generating a jwt in go, no magic
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": userID,
"exp": time.Now().Add(15 * time.Minute).Unix(),
})
signed, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
if err != nil {
return "", fmt.Errorf("signToken: %w", err)
}the js ecosystem's strength is also its weakness: it abstracts so much that you can ship without understanding.
still learning. still getting confused. still occasionally wondering why i didn't just stick with express.
but then something clicks — a pointer makes sense, an error handling pattern feels right, raw sql stops feeling scary — and i remember why i started.
go is making me a better developer. not because it's better than js, but because it forces me to think.
and thinking, it turns out, is the whole point.
if you're a js dev curious about go: do it. give yourself a few weeks of genuine discomfort. the other side is worth it.