r/golang

▲ 34 r/golang

How do you plan your backend logic before writing code?

When I have an endpoint with more than 10 business logic steps, my brain can't keep track of it all at once. So I end up drawing it out on paper: what functions exist, what each accepts, what it returns, how they're related. Is it just me? How do you deal with this? Is there a tool that really helps with this, or is paper/Notion still the best option?

reddit.com
u/Ok_Engine_3116 — 15 hours ago
▲ 28 r/golang

Use Values for Null Safety

I'm trying to understand the idiomatic Go approach for expressing non-nullability.

As I understand it:

  • A struct value can never be nil.
  • A pointer (*T) can be nil, so it's commonly used when the absence of a value is meaningful.

For example:

type User struct {
    Name string
}

// User can never be nil.
func ProcessValue(user User) {
    // ...
}

// User may be nil.
func ProcessPointer(user *User) {
    // ...
}

The problem is that using a value has two different semantics:

  1. It guarantees the argument is non-nil.
  2. It copies the entire struct when passed to a function or assigned.

For small structs this isn't a concern, but for very large structs the copy can be expensive. In those cases I'd prefer to pass a pointer, but then I've lost the compile-time guarantee that the value isn't nil.

For example:

type LargeStruct struct {
    Data [1024 * 1024]byte
}

func Process(s LargeStruct) {
    // Copies the entire struct.
}

Is there an idiomatic way in Go to express "this must never be nil" while still passing a pointer?

Or is the accepted Go approach simply to use *T and rely on documentation and runtime checks when non-nil is required?

reddit.com
u/Sad_Importance_1585 — 17 hours ago
▲ 20 r/golang

Five years of Go libraries for document layout and PDF generation

Most Go PDF libraries focus on drawing primitives or generating reports from templates. Over the last five years I've been working on a different approach: a layout engine that handles paragraphs, pagination, tables, images, footnotes, etc., with a strong focus on accessible PDFs.

That started with boxesandglue, but gradually grew into a small ecosystem:

  • boxesandglue: a Go library for document layout and PDF generation
  • htmlbag/bagme: HTML/CSS to PDF built on top of boxesandglue
  • glu: Markdown to accessible PDF including math
  • plus supporting libraries for XML, XPath, XSLT and document processing

Everything is open source, and I recently put together an interactive map showing how the projects relate to each other:

https://constellation.speedata.de

I'd be interested in hearing what other Go developers think.

My background is another (OpenSource) software which I use for my work (the speedata Pubisher, started with it almost 15 years ago). It is built on top of LuaTeX (the modern typesetting software with excellent typography) and focusses on product catalogs and data sheets. The handling of the deployment (I use custom Go based shared libraries which are linked during runtime to the LuaTeX binary and accessed from within Lua) is rather complicated, so my goal was to re-create TeX's typography in a modern setting.

u/Immediate_Life7579 — 17 hours ago
▲ 116 r/golang

Has Go Started Moving Away from Its Original Philosophy?

One of the reasons I originally liked Go was its philosophy: there was usually one obvious way to solve a problem. That simplicity made codebases easier to read, easier to review, and easier for new developers to understand.

Generics solved a real problem. Before Go 1.18, it was common to duplicate code for different types or fall back to interface{}. In that sense, generics were a worthwhile addition.

However, I feel the feature is intentionally conservative. For example, Go still doesn't support generic methods, which limits some abstractions that are common in other languages. While I understand the design rationale, it sometimes feels like Go added generics without embracing the full set of patterns they enable.

The new iterator support leaves me with a similar feeling. Now there are multiple ways to express iteration depending on the API. None of them are inherently bad, but one of Go's original strengths was minimizing the number of equally valid approaches. As the language grows, that consistency becomes harder to preserve.

My concern isn't that these features are poorly designed. My concern is that each new feature moves Go a little further away from the minimal language that originally attracted many of its users.

Sometimes it feels like Go is trying to borrow ideas from languages like Rust or TypeScript while intentionally stopping short of matching their expressive power. The result is a language that is becoming more capable, but also more complex.

I still enjoy writing Go, but I sometimes wonder whether the project would have benefited more from doubling down on performance, tooling, diagnostics, and runtime improvements rather than expanding the language itself.

I'm curious how others see this. Has Go found the right balance between simplicity and expressiveness, or do you think it's gradually drifting away from its original philosophy?

reddit.com
u/AMiR_ViP — 1 day ago
▲ 342 r/golang

"go fix" on Go 1.26+ is awesome

If you haven't tried the new "go fix" yet, give it a spin.

It's a proper revival of the old "gofix" idea. In Go 1.26, it was rebuilt on top of the Go analysis framework. So now it can modernize your code with newer language and stdlib features.

It respects the Go version in your module. If your "go.mod" says "go 1.26", it suggests Go 1.26-compatible changes. It doesn't rewrite your code into something your module hasn't opted into.

For teams using LLMs, this is great. You don't need to keep leaving PR comments like “use the newer API here” or “we don't write that pattern anymore.” Run it locally or on the CI instead.

Start from a clean git state:

go fix -diff ./...

Then apply it:

go fix ./...

Then run it again.

Some fixes expose more fixes. The Go team recommends rerunning it, and in practice two passes often catches more than one.

Some useful analyzers:

You can also run one analyzer at a time if you want smaller PRs:

go fix -newexpr ./...
go fix -forvar ./...

That's useful when one pass touches a lot of files and you don't want one giant mixed cleanup patch.

The other neat bit is //go:fix inline. Library authors can use it to help users migrate from old APIs to new APIs. That's much better than deprecating something and hoping everyone reads the changelog.

You can also write your custom analyzer to enforce your own rules. I am writing a few for fun.

The Go blog has two good posts on it:

I ran it on a large RPC service, and "newexpr" cleaned up a pile of pointer helper calls. Extremely satisfying.

reddit.com
u/sigmoia — 1 day ago
▲ 149 r/golang+2 crossposts

Kako izvući maksimalne performanse - arhitektura/sistem dizajn blog

Pozdrav svima, pre par nedelja sam pisao o konvertovanju minified stack trace-a nazad u čitljiv. Ovo je bilo lako odraditi ali nije bilo optimalno za platformu koja procesira desetine hiljada ovakvih dogadjaja u sekundi sa gomile razlicitih klijenata (js, ts, flutter, ios).

Ovaj blog je opis mog pristupa problemu sa 3 različite faze od kojih svaka dodaje nešto u odnosu na prethodnu. Na kraju radim poredjenje performansi sa Honeycomb implementacijom koja koristi Sentry biblioteku u pozadini (spoiler: ovaj dizajn ima i do 32x veći throughput).

Ukoliko vas interesuje arhitektura i dizajn sistema kao i posledice istog na performanse možda vam blog bude interesantan. Takodje malo priča i o mmap-u koji do sad nisam koristio a koji je bio ključan za ovaj sistem.

Ukoliko imate pitanja ili sugestije pišite slobodno, ako ste voljni da podrzite projekat možete da zapratite blog, bacite zvezdicu na github.com/tracewayapp/traceway ili se ubacite u discord https://discord.gg/RZq9NT62nc

tracewayapp.com
u/narrow-adventure — 2 days ago
▲ 24 r/golang+1 crossposts

Postgres DB TUI

Couldn't find a DB TUI that had all the features I wanted, so I decided to create it.

Still in active development. Obviously written in Go and inspired by Lazygit.

https://github.com/davesavic/pgsavvy

Fully customisable vim-style keybindings + a heap of useful features.

Hopefully you find it as useful as I have!

u/Savalonavic — 2 days ago
▲ 104 r/golang

Are you using Makefile?

Hi everyone!

I’m currently in the early stages of learning Go. I see a lot of projects using Makefiles, and I’m wondering: should I dive into them right now, or is it better to focus purely on Go features first?

The community poll option is disabled here, so please share your thoughts in the comments. When did you start using Makefiles in your Go workflow, and is it a must-have for a beginner? Thanks!

reddit.com
u/Perfon_ — 3 days ago
▲ 18 r/golang

Anybody have any advice to dive deeper into go

So to preface this I'm dyslexic as fuck, hate reading docs of any form. I know the golang docs are good but really struggle to "connect the dots" with a lot of it. My dyslexia is less like letters jumping around and more can't hold onto the written word past about 2, hence long post.

Are there any concepts or particular sharp edges or things to be aware of. Videos I can digest much easier because they usually do complete examples so I can see the pattern and memorise it. I get the concept eventually because it's about experimenting with the pattern, break it improve it etc. A lot of them are more tutorials and less about "things that will catch you out if you're not aware of them" if that makes sense?

Would appreciate any advice!

reddit.com
u/dapper_gadgey — 2 days ago
▲ 16 r/golang

Any use case for a generic interface that you actually used?

I have used generic functions for example:

// Ptr returns a pointer to the given value.
func Ptr[T any](v T) *T {
return &v
}

Or even on structs, but I never got a proper use case for interfaces with generics, something like

type Namer[T any] interface {
    // What would go here?
}

Do you have a specific use case where it is a no brainer to use generic interfaces?

Thanks.

reddit.com
u/PsychoDude02 — 2 days ago
▲ 112 r/golang+1 crossposts

The Rise of the Command Line: building a new IDE (2017–2026). Rune Blog

Author here. This is a nine-year account of building Rune, a new IDE for Go. It started when my Vim's go-to-definition broke in 2017 and I decided to build my own editor rather than adopt an IDE. Happy to answer questions.

rune.build
u/ernestrc — 3 days ago
▲ 31 r/golang

How to get hired as a Golang developer?

I have one year of production experience with Go and have recently worked extensively on concurrency patterns. Do you have any suggestions?

EDITED: I know TypeScript, Rust and Python, including the popular frameworks for these languages

reddit.com
u/I-m_ALIVE — 3 days ago
▲ 34 r/golang

I built a rule engine, and I need feedback

Well...this fun experiment took about 5 months of my free time (no AI slop i promise). I got interested in rule engines early this year so i started building one in Go to fit my exact needs. I'm posting this because i've been staring at it alone for too long and I would really like some outside eyes to help with direction. I think it's in a good state now to share with you all.

I'm not sure how to write this post so maybe the best approach is to show an example and work through it:

signal GiveAward(pid, award)

// add more here: emojis, curly quotes, etc.
const MARKERS = ["—"]

rule SlopFilter {
    text = strings::lower(input.text)

    out score = len(arrays::filter(MARKERS, |m| strings::contains(text, m)))
    out slop  = score > 0

    emit GiveAward(input.id, "bravo") when !slop
}

What you see above is a basic nodora ruleset. A rule is a pure function: the same input always yields the same output. Evaluating a rule gives you back two things: outputs (facts about the input) and signals (things that should happen next). Notice that the rule does not constrain the output shape. The output can be any value (see the out keyword), not just a boolean decision. The input-output contract between the rules and consumers is up to you to define.

A signal is a named event the rule can fire off, like "give this post an award" or "flag for review" type thing. An asynchronous side effect of the rule. Declaring it doesn't do anything, it just says this signal exists and takes these arguments. The engine decides through emit statement when to fire it, which you can listen for.

Using the nodora CLI, we can compile this example with:

$ nodora compile -f ./example.ruleset

Then go through evaluation:

$ echo '{"id":1,"text":"This is a great post"}' | nodora eval -f ./example.json --stdin

which outputs:

{"outputs":{"score":0,"slop":false},"emitted_signals":[{"name":"GiveAward","args":[1,"bravo"]}]}

We can act on a signal with:

$ echo '{"id":1,"text":"This is a great post"}' | nodora eval -f ./example.json -e GiveAward="echo giving {2} award to post with id {1}" --stdin

{"outputs":{"score":0,"slop":false},"emitted_signals":[{"name":"GiveAward","args":[1,"bravo"]}]}
giving bravo award to post with id 1

If we put an em dash in the text and evaluate again:

$ echo '{"id":1,"text":"This is a great post — really."}' | nodora eval -f ./example.json --stdin

{"outputs":{"score":1,"slop":true},"emitted_signals":[]}

There is a lot more to it, you can read the full docs at nodora.org/docs. The engine is fully open-source (github repo).

Note: In most cases you probably won't use the CLI for evaluation. Its mainly there for quick testing. You'd usually embed the engine directly into your go project, or use one of the language bindings: js (wasm) and rust (working on others)

I'd love to hear your overall thoughts and feel free to ask anything :)

u/dafzu — 3 days ago
▲ 91 r/golang

Generic methods are finally there in 1.27 and I already have a complaint

I’ve been going through the release notes for 1.27 RC1 and I have my own notes.

I was excited to see that generic methods are finally there, I wanted these for a long time! Having said that, I’m also disappointed in them as well. AFAIU, they let a method declare its own type parameters, but they don't let you specify a different constraint on the type parameters of the receiver. So something like this still wouldn’t work:

type List[T any] []T
func (x List[T comparable]) Equal(y List[T]) bool { ... }

The receiver can only name T, it can't re-constrain it to comparable. So you're back to dropping down to a package-level func Equal[T comparable](a, b List[T]) bool, which defeats the purpose for me.

Am I misreading the spec, or is narrowing the receiver's constraint still not possible? Would love to be wrong here.

Not to be a total killjoy, there are also things I genuinely love about this release. Especially having uuid in the standard library (IMO it should have been there years ago) and the simd package (I know it’s still experimental, but it’s a cool addition that I hope over time gets adopted in some of the widely-used libraries, giving us all better performance :D).

reddit.com
u/Nika_84 — 4 days ago
▲ 132 r/golang+17 crossposts

Walks the full cmd/compile pipeline in order: package names, data structures, and the SSA construction that drives inlining, escape analysis, bounds-check elimination, and register allocation, with flags to observe each phase directly.

This one took a while, it's probably the longest thing I've written on this blog. I wanted to do a proper end-to-end walkthrough of cmd/compile: real package names, real data structures, diagrams for the AST and SSA CFG, and the flags you actually need (-m, -m=2, GOSSAFUNC, -S) to observe each phase yourself rather than just take my word for it.

Covers the full pipeline: lexer → parser → type checker → IR lowering → SSA construction → optimization passes (inlining, escape analysis, BCE, nil check elimination, register allocation) → architecture-specific code emission.

Hope it's useful — happy to answer questions or push back on anything that looks wrong.

blog.gaborkoos.com
u/OtherwisePush6424 — 4 days ago
▲ 146 r/golang

I've switched from Dotnet to Go and I have some tensions with the language. has anyone resolved these?

I've been writing in C# and ASP.Net for most of my career, and 4 months ago I switched to Go.

So far I really like the concurrency model, how robust the standard lib is with anything to do with networking, and the general "vibe" of the language.

But there are some tensions I feel when I'm writing it that I can't get past, and I'm not sure whether there's a click that needs to happen or that's just the tradeoffs that Go makes.

  1. In Go every package is a dir, every subpackage is a subdir, and marking a subpackage as internal to the package it's in require an "internal" dir. I find myself avoiding splitting logic and concerns into subpackages even when I think I should because I don't want to clutter the repo. Is this just something you have to power through?

  2. I usually favor baking business rules into types, I found it helps catch bugs at development time, It is possible in Go, but it feels like it requires more ceremony, simply declaring a type over a primitive doesn't let you constrain its creation in any way, even with structs it's hard to make constructor functions a must, and with enums and union types not part of the language it takes a lot of code to constrain a field to a closed set of values or blocking invalid combinations of fields from being set together. Are there patterns I should use that make those easier?

  3. I find myself putting a lot of thought into DI, configuration layering, input binding and validation, all stuff I used to get from the framework without putting much effort into it, those are very much "opt in" in Go, how do you make sure the all contributers opt in consistently?

I get that all of those points are by design, the Go philosophy favors small microservices with flat codebases and little abstraction to keep everything explicit, But it seems like keeping a codebase maintainable in Go requires consistent discipline and some craftsmanship across the team, And as an individual contributor, even a senior one, I don't always call the shots, So how do you navigate this in a long running project with people coming and going?

reddit.com
u/Ok_Brain208 — 5 days ago
▲ 13 r/golang

Package to redact tokens/secrets

I am looking for a package to redact tokens/secrets from a string.

I found trufflehog, but it is AGPL, which means I must not use that package.

I want common patterns of secrets to be found and replaces with [REDACTED].

Example: ghp_.... or secret-token: (RFC8959)

Please do not tell me to use regex. I am looking for a package which already knows common patterns of tokens/secrets.

BTW, there is gitleaks, but it is a cli tool, not a package for redacting.

How would you solve that?

reddit.com
u/guettli — 4 days ago
▲ 86 r/golang+2 crossposts

How to split 10GB JSON files in seconds without hitting RAM limits

We had this classic pain point on our project: constantly chewing through massive JSON arrays. Catalogs, analytics dumps, ML datasets — files ranging from a couple hundred megabytes to tens of gigabytes.

The task was stupidly simple: split a giant JSON array into individual elements so we could chunk them or throw them into parallel processing. No data transformation, no querying by keys. We literally just needed to find where each chunk starts and ends.

Naturally, we started with the classic approach: json.Unmarshal -> slice -> json.Marshal. On a 10GB file, memory consumption went to the moon. We ended up spending more time fighting the Go garbage collector (GC) than doing actual work.

And then it clicked: to just move the data around, we don't need to understand what's inside it. We just need to find the boundaries.

Stop parsing, start scanning

Every parser out there (even the ultra-fast ones like sonic or simdjson) still builds a tree in memory. Instead, you can just treat the JSON as a raw byte stream. Look for structural markers, find the edges, and cut.

The entire logic boils down to a tiny state machine:

  1. Nesting counter: { and [ go +1, } and ] go -1.
  2. String tracking: keep track of when you enter "..." so you don't accidentally react to brackets inside a text field.
  3. Escapes: a \" inside a string is a trap, not the end of the string.
  4. The boundary: whenever your nesting depth is exactly 0, any comma , is where you split.

That’s it. We don't care about keys or values. We don't allocate a single byte, we just return memory views (slices) of the original buffer.

Here’s what the concept looks like in Go (oversimplified, ignoring string logic):

gofunc findElements(data []byte) []Chunk {
    var chunks []Chunk
    depth := 0
    start := 0
    for i, b := range data {
        switch b {
        case '{', '[':
            depth++
        case '}', ']':
            depth--
        case ',':
            if depth == 0 {
                chunks = append(chunks, Chunk{Start: start, End: i})
                start = i + 1
            }
        }
    }
    if start < len(data) {
        chunks = append(chunks, Chunk{Start: start, End: len(data)})
    }
    return chunks
}

Obviously, this naive code will break on the first tricky whitespace or string, but you get the point. We aren't parsing. We are scanning.

Why is this so damn fast?

  1. Zero allocations in the hot loop. You're just handing back data[start:end]. No new objects, no copying strings, no building hash maps.
  2. Hardware absolutely loves it. Your entire working state is basically two integers. It easily fits in L1 cache, and memory reads are strictly sequential.
  3. The branch predictor is happy. A simple state machine with highly predictable transitions is infinitely easier for the CPU to digest than a full parser juggling dozens of token types.

Look at how much work we are skipping:

Step Standard Parser Boundary Scanner
Read bytes
Classify tokens Only {}[]"\ and ,
Build hash maps
Allocate strings
Allocate slices
Type conversion
What you get back []MyStruct [][]byte (pointers to original buffer)

We are literally throwing away 80% of the overhead.

But how fast is it actually?

I got a bit carried away and polished this into a production-ready tool. I added proper string handling, escape tracking, and rewrote the hot loop in AVX2 assembly (chewing through 32 bytes per cycle using SIMD bitmasks).

Tbh, the results surprised even me:

Approach What it does Throughput Memory Overhead
encoding/json Full parse → Go structs ~107 MB/s 3-4x input size
sonic / simdjson-go Optimized parse → structs/AST ~400–700 MB/s ~1.1x
My AVX2 scanner Just finds boundaries ~4.1 GB/s ~1.0x (zero extra)

At 4.1 GB/s, the algorithm isn't even the bottleneck anymore. It's bottlenecked by the RAM's read bandwidth. The CPU is just sitting there waiting for the next cache line to arrive.

The catch (Tradeoffs)

Because I went the unsafe and raw assembly route for maximum speed, you have to pay the price:

  • Platform-specific: The AVX2 branch only works on amd64. For ARM (hello MacBooks), you need a pure Go fallback.
  • Memory lifecycle danger: You are getting slices that point directly to the original buffer. If that []byte gets overwritten or GC'd while you're still working with the chunks... it's going to hurt.
  • No validation: The scanner takes your word that the JSON is valid. Feed it garbage, and it will silently slice up garbage.

TL;DR

The biggest insight was stupidly simple: stop thinking "I need to parse this JSON" and start thinking "I need to find boundaries in a byte stream". Once I changed my perspective, the code wrote itself and the performance gap was massive.

Has anyone else suffered through this? How do you guys route or chunk massive JSON payloads in production when you simply can't fit them into RAM?

If anyone wants to poke around the assembly or run the benchmarks, the repo is here: https://github.com/GenshIv/silentjson

u/No-Job-5616 — 5 days ago
▲ 132 r/golang

Is anyone else finding that AI-generated Go code fights against standard idioms/project layout?

I’ve been using Cursor/Claude to help scaffold a medium-sized backend in Go. While the velocity is great for simple handlers or repository functions, I feel like I'm constantly fighting the tool on project structure and idiomatic code.

The AI keeps trying to introduce unnecessary abstractions, mixes up package boundaries, or tries to write things in a way that feels like it's treating Go like Java or TypeScript. It makes the code compile and pass basic tests, but the global project layout quickly starts drifting from standard clean architecture practices unless I manually review and rewrite every single file structure.

For those using AI tools on larger Go codebases, how are you enforcing strict idiomatic guidelines on the model? Or do you find it's better to just write the structural boilerplate yourself and only use AI for isolated unit tests?

reddit.com
u/CrazyGeek7 — 5 days ago
▲ 75 r/golang

Who's Hiring

This is a monthly recurring post. Clicking the flair will allow you to see all previous posts.

Please adhere to the following rules when posting:

Rules for individuals:

  • Don't create top-level comments; those are for employers.
  • Feel free to reply to top-level comments with on-topic questions.
  • Meta-discussion should be reserved for the distinguished mod comment.

Rules for employers:

  • To make a top-level comment you must be hiring directly, or a focused third party recruiter with specific jobs with named companies in hand. No recruiter fishing for contacts please.
  • The job must be currently open. It is permitted to post in multiple months if the position is still open, especially if you posted towards the end of the previous month.
  • The job must involve working with Go on a regular basis, even if not 100% of the time.
  • One top-level comment per employer. If you have multiple job openings, please consolidate their descriptions or mention them in replies to your own top-level comment.
  • Please base your comment on the following template:

COMPANY: [Company name; ideally link to your company's website or careers page.]

TYPE: [Full time, part time, internship, contract, etc.]

DESCRIPTION: [What does your team/company do, and what are you using Go for? How much experience are you seeking and what seniority levels are you hiring for? The more details the better.]

LOCATION: [Where are your office or offices located? If your workplace language isn't English-speaking, please specify it.]

ESTIMATED COMPENSATION: [Please attempt to provide at least a rough expectation of wages/salary.If you can't state a number for compensation, omit this field. Do not just say "competitive". Everyone says their compensation is "competitive".If you are listing several positions in the "Description" field above, then feel free to include this information inline above, and put "See above" in this field.If compensation is expected to be offset by other benefits, then please include that information here as well.]

REMOTE: [Do you offer the option of working remotely? If so, do you require employees to live in certain areas or time zones?]

VISA: [Does your company sponsor visas?]

CONTACT: [How can someone get in touch with you?]

reddit.com
u/jerf — 4 days ago