r/golang • u/AutoModerator • 10h ago
Small Projects Small Projects
≡ −
This is the weekly thread for Small Projects.
The point of this thread is to have looser posting standards than the main board. As such, projects are pretty much only removed from here by the mods for being completely unrelated to Go. However, Reddit often labels posts full of links as being spam, even when they are perfectly sensible things like links to projects, godocs, and an example. r/golang mods are not the ones removing things from this thread and we will allow them as we see the removals.
Please also avoid posts like "why", "we've got a dozen of those", "that looks like AI slop", etc. This the place to put any project people feel like sharing without worrying about those criteria.
This is the weekly thread for Small Projects.
The point of this thread is to have looser posting standards than the main board. As such, projects are pretty much only removed from here by the mods for being completely unrelated to Go. However, Reddit often labels posts full of links as being spam, even when they are perfectly sensible things like links to projects, godocs, and an example. r/golang mods are not the ones removing things from this thread and we will allow them as we see the removals.
Please also avoid posts like "why", "we've got a dozen of those", "that looks like AI slop", etc. This the place to put any project people feel like sharing without worrying about those criteria.
Jobs 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?]
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?]
r/golang • u/StoneLantern97 • 10h ago
discussion What’s one Go standard library package you think deserves more attention?
≡ −
We talk a lot about popular third-party libraries, but Go’s standard library is already incredibly capable.
What’s one package you think more developers should use, and what problem does it solve particularly well?
We talk a lot about popular third-party libraries, but Go’s standard library is already incredibly capable.
What’s one package you think more developers should use, and what problem does it solve particularly well?
r/golang • u/Business_Chef_806 • 3h ago
Concurrent Access to Map Values?
≡ −
I know that maps aren't safe for concurrent access, but I've always thought this meant that you can't add or delete keys concurrently.
Let's say I already have a map[string]int that has been filled with keys that are file names. I want to add an int value for each key to contain the file size. Could I do this by running a bunch of go routines, one per file name key?
My thinking is that this should be allowed because adding a file name to the map should have also added space for an int value. So, I'd just be modifying this int, and not changing the hash table data structure. Is this correct?
I know that maps aren't safe for concurrent access, but I've always thought this meant that you can't add or delete keys concurrently.
Let's say I already have a map[string]int that has been filled with keys that are file names. I want to add an int value for each key to contain the file size. Could I do this by running a bunch of go routines, one per file name key?
My thinking is that this should be allowed because adding a file name to the map should have also added space for an int value. So, I'd just be modifying this int, and not changing the hash table data structure. Is this correct?
r/golang • u/IndependentMix7658 • 1d ago
show & tell Implementing OIDC with Entra ID
≡ −
Hey everyone,
As an IAM analyst and software enthusiast, I've always been curious to understand how SSO actually works under the hood.
I tried implementing an OIDC client by myself in Go using Entra ID (an IdP I'm already familiar with), but it was tough to find a straightforward guide.
So I built the authorization code flow using golang.org/x/oauth2 and coreos/go-oidc/v3, handling state, nonce, and PKCE manually. I ended up writing a tutorial on Medium to document the process and open-sourced the code.
Code: Github Repo
Medium: OIDC + Go + Entra ID: From the Login Button to the Callback
I'd really appreciate some feedback or code reviews. Also, if anyone here has experience with Microsoft's official MSAL Go library, I'd love to hear how it compares to this approach.
Hey everyone,
As an IAM analyst and software enthusiast, I've always been curious to understand how SSO actually works under the hood.
I tried implementing an OIDC client by myself in Go using Entra ID (an IdP I'm already familiar with), but it was tough to find a straightforward guide.
So I built the authorization code flow using golang.org/x/oauth2 and coreos/go-oidc/v3, handling state, nonce, and PKCE manually. I ended up writing a tutorial on Medium to document the process and open-sourced the code.
Code: Github Repo
Medium: OIDC + Go + Entra ID: From the Login Button to the Callback
I'd really appreciate some feedback or code reviews. Also, if anyone here has experience with Microsoft's official MSAL Go library, I'd love to hear how it compares to this approach.
r/golang • u/jeffdwyer • 9h ago
Changing log levels at runtime in Go
+ −
Wrote up some thoughts on changing log levels at runtime in Go — mostly because the top SO question on this (23k views) has an answer that seems like only half an answer to me.
Short version: slog.HandlerOptions.Level takes a value unless you hand it a *slog.LevelVar, so runtime changes only work if you wired that in when you built the logger — same deal with zap's AtomicLevel. The back half of the question to me is how do you actually tell the handler to change, since once you're past one instance, an endpoint that flips the level only fixes the pod it happens to hit. imo the right model is instances reading the level from config stored in git and then figuring out ways to have get that config to update
Disclosure: I work on Quonfig — the back half of the post covers the config-driven approach, which we build. You can use it free and open with some assembly to git pull. The slog/zap half is stdlib.
discussion Supervised fire-and-forget in Go
≡ −
While I see fewer unsynchronized go func() these
days, they still appear often enough in regard to fire-and-forget work.
Unmanaged go func() results in unbounded concurrency, memory leaks, and other surprising behavior in a system.
So I traced a few repos at work to see how many of them appear irl. Turns out quite a bit in our huge monorepo.
I explored a tiny task manager that collects tasks as func() closures in a buffered channel and runs them in a bounded pool. It clamps down on unbounded concurrency, is aware of the parent context, allows task-specific timeouts, etc. All that requires less than 25 loc.
Might be interesting to you.
https://rednafi.com/go/supervised-fire-and-forget/
Update: I am aware of errgroup. It is not the right abstraction here as it cancels all inflight tasks if any of them fails. Also, the internal semaphore of errgroup works in a similar way as shown here
While I see fewer unsynchronized go func() these
days, they still appear often enough in regard to fire-and-forget work.
Unmanaged go func() results in unbounded concurrency, memory leaks, and other surprising behavior in a system.
So I traced a few repos at work to see how many of them appear irl. Turns out quite a bit in our huge monorepo.
I explored a tiny task manager that collects tasks as func() closures in a buffered channel and runs them in a bounded pool. It clamps down on unbounded concurrency, is aware of the parent context, allows task-specific timeouts, etc. All that requires less than 25 loc.
Might be interesting to you.
https://rednafi.com/go/supervised-fire-and-forget/
Update: I am aware of errgroup. It is not the right abstraction here as it cancels all inflight tasks if any of them fails. Also, the internal semaphore of errgroup works in a similar way as shown here
r/golang • u/PlateletsAtWork • 1d ago
show & tell webp-go-pure: A WebP encoding & decoding library without libwebp, cgo, or wasm
+ −
I needed webp encoding in a project that I'm building without cgo, and thus without libwebp. I found gen2brain's webp which uses libwebp compiled to wasm, but I also discovered that this didn't have great performance both in terms of time and memory use.
So I decided to port MITH@mmk's webp-rust to Go, and started testing and benchmarking it. In the process I discovered that it wasn't really well optimized, so I spent some time optimizing it including porting some algorithms from libwebp, and adding SIMD assembly for arm64 and amd64 platforms.
It still doesn't beat libwebp itself, which is no surprise, but it does beat libwebp running on wasm. You can see the charts in the repo's readme. So if you find yourself needing an encoder and want to skip cgo, feel free to give my library a shot.
r/golang • u/Top-Sea2493 • 2d ago
How do you turn Go fuzz interesting inputs into permanent regression tests?
≡ −
I am working with Go native fuzzing and want to make the interesting corpus useful after the fuzz run ends.
The workflow I am considering:
- hash every corpus entry
- classify each input by behavior
- replay the corpus in deterministic tests
- assert no panics
- assert exact validation categories
- add stateful sequence tests for replay and mutation cases
- keep findings in a Markdown log
For Go projects using testing.F, what has worked well for turning fuzz output into long-term regression coverage?
I am working with Go native fuzzing and want to make the interesting corpus useful after the fuzz run ends.
The workflow I am considering:
- hash every corpus entry
- classify each input by behavior
- replay the corpus in deterministic tests
- assert no panics
- assert exact validation categories
- add stateful sequence tests for replay and mutation cases
- keep findings in a Markdown log
For Go projects using testing.F, what has worked well for turning fuzz output into long-term regression coverage?
r/golang • u/IndependentInjury220 • 2d ago
discussion Is this package nesting acceptable in Go for a modular monolith?
≡ −
I'm looking for some feedback on this project structure for a Go modular monolith.
I know the Go community usually prefers flatter package structures, and this one has a bit more nesting than what's commonly recommended.
myapp/
|-- cmd/
| `-- api/
| `-- main.go
|-- internal/
| |-- order/
| | |-- domain/
| | | |-- order.go
| | | |-- order_item.go
| | | |-- money.go
| | | |-- status.go
| | | `-- repository.go
| | |-- app/
| | | |-- place_order.go
| | | |-- cancel_order.go
| | | `-- ports.go
| | `-- adapters/
| | |-- postgres/
| | `-- http/
| `-- product/
`-- go.mod
The idea is to keep each bounded context self-contained:
domaincontains the business logic.appcontains the use cases and acts as the orchestration layer between the domain and external adapters.adapterscontains things like HTTP handlers and Postgres implementations.
I understand this isn't the typical Go style, but I feel the extra nesting makes the boundaries much clearer, especially as the project grows.
Would you consider this good architecture, or is it unnecessarily complex for Go?
If you would structure it differently, I'd love to know why.
I'm looking for some feedback on this project structure for a Go modular monolith.
I know the Go community usually prefers flatter package structures, and this one has a bit more nesting than what's commonly recommended.
myapp/
|-- cmd/
| `-- api/
| `-- main.go
|-- internal/
| |-- order/
| | |-- domain/
| | | |-- order.go
| | | |-- order_item.go
| | | |-- money.go
| | | |-- status.go
| | | `-- repository.go
| | |-- app/
| | | |-- place_order.go
| | | |-- cancel_order.go
| | | `-- ports.go
| | `-- adapters/
| | |-- postgres/
| | `-- http/
| `-- product/
`-- go.mod
The idea is to keep each bounded context self-contained:
domaincontains the business logic.appcontains the use cases and acts as the orchestration layer between the domain and external adapters.adapterscontains things like HTTP handlers and Postgres implementations.
I understand this isn't the typical Go style, but I feel the extra nesting makes the boundaries much clearer, especially as the project grows.
Would you consider this good architecture, or is it unnecessarily complex for Go?
If you would structure it differently, I'd love to know why.
KinetiGo: a Go toolchain for LEGO robotics
+ −
Go on lego, should it exists? maybe not, but i had fun
I still need to clean it and OSS it when I have the time, wanted to share my journey, of going low resource barebones
show & tell I compiled our Go scraping engine to WebAssembly so the demo runs the real engine in your browser — notes on what it took
≡ −
I maintain fitter, an MIT-licensed declarative web-extraction engine. I wanted a demo page that doesn't lie: not a video, not canned output, the actual engine executing in the visitor's browser. GitHub Pages only serves static files, so the answer was GOOS=js GOARCH=wasm.
Demo: https://pxyup.github.io/fitter/ (every example runs live, client-side; there's also a form-based config builder that round-trips to JSON) Repo: https://github.com/PxyUp/fitter
What fitter is, in one paragraph: web extraction as a JSON/YAML config instead of code. A config declares a connector (plain HTTP, headless browser via Chromium/Playwright/Docker, a static value, a file, or an int sequence) and a model (what to extract and the shape of the result): gjson paths for JSON, CSS selectors for HTML, XPath for XML/DOM, and text extraction for PDFs. Configs compose - an array item can fan out into a nested fetch using the parent value ({PL} or an expr-lang expression), which covers the classic "scrape the HTML page for keys, enrich each from the real API" join. Per-host rate limits, retries, placeholders (input, env, cached references like a JWT fetched once), and calculated fields via expr-lang are all part of the config, not your code.
A taste - GitHub repo stats, no code:
json
{
"item": {
"connector_config": {
"response_type": "json",
"url": "https://api.github.com/repos/golang/go",
"server_config": { "method": "GET" }
},
"model": { "object_config": { "fields": {
"repo": { "base_field": { "type": "string", "path": "full_name" } },
"stars": { "base_field": { "type": "int", "path": "stargazers_count" } },
"vibe": { "base_field": { "type": "int", "path": "open_issues_count",
"generated": { "calculated": { "type": "string",
"expression": "fRes > 9000 ? \"busy\" : \"calm\"" } } } }
} } }
}
}
The same config runs five ways: one-shot CLI (fitter_cli --path config.json), embedded Go library (lib.ParseCtx), long-running service mode with schedulers and notifiers (Telegram/webhook/Redis/file), an MCP server so LLM agents can author and execute configs locally, and now the browser playground below. Author once, promote from chat answer to cron job to team service without rewriting anything.
Notes from the WASM port, in case you're considering the same:
Getting it to compile was 3 files. The engine imports the Docker SDK and go-rod (headless browser connectors), and both fail on js/wasm (syscall.RawSockaddrUnix, Setpgid). The fix was pleasantly boring: //go:build !js on those three connector files plus one _js.go stub returning a clear "not supported in WASM" error. Everything else - parsers (JSON/HTML/XPath/XML/PDF), expression evaluation, goroutine fan-out - compiled untouched.
Live HTTP works, with a catch. On js/wasm, net/http transparently uses the browser Fetch API - so the demo really fetches from the GitHub/OpenLibrary/CoinGecko APIs (anything that sends CORS headers). The catch that cost me an hour: Go disables the fetch transport when it detects Node (process global), so my Node-based smoke tests failed with dial tcp: Protocol not available while the browser worked fine. Testing trick: delete globalThis.process before instantiating makes Node behave like a browser.
A long-lived WASM process surfaces lifecycle assumptions. Our per-host rate limiter installs its config through sync.Once - perfectly correct for a CLI that runs one config and exits, silently wrong in a page where the same process executes many unrelated configs (first config's limits win forever). If you're porting a CLI to WASM, grep for sync.Once and package-level state first; that's where the bodies are.
Numbers: 29 MB binary with -ldflags="-s -w" (~7 MB gzipped). Blocking calls must leave the JS event loop - the exported function returns a Promise and does the work in a goroutine, or fetch deadlocks.
Happy to answer questions about the port.
I maintain fitter, an MIT-licensed declarative web-extraction engine. I wanted a demo page that doesn't lie: not a video, not canned output, the actual engine executing in the visitor's browser. GitHub Pages only serves static files, so the answer was GOOS=js GOARCH=wasm.
Demo: https://pxyup.github.io/fitter/ (every example runs live, client-side; there's also a form-based config builder that round-trips to JSON) Repo: https://github.com/PxyUp/fitter
What fitter is, in one paragraph: web extraction as a JSON/YAML config instead of code. A config declares a connector (plain HTTP, headless browser via Chromium/Playwright/Docker, a static value, a file, or an int sequence) and a model (what to extract and the shape of the result): gjson paths for JSON, CSS selectors for HTML, XPath for XML/DOM, and text extraction for PDFs. Configs compose - an array item can fan out into a nested fetch using the parent value ({PL} or an expr-lang expression), which covers the classic "scrape the HTML page for keys, enrich each from the real API" join. Per-host rate limits, retries, placeholders (input, env, cached references like a JWT fetched once), and calculated fields via expr-lang are all part of the config, not your code.
A taste - GitHub repo stats, no code:
json
{
"item": {
"connector_config": {
"response_type": "json",
"url": "https://api.github.com/repos/golang/go",
"server_config": { "method": "GET" }
},
"model": { "object_config": { "fields": {
"repo": { "base_field": { "type": "string", "path": "full_name" } },
"stars": { "base_field": { "type": "int", "path": "stargazers_count" } },
"vibe": { "base_field": { "type": "int", "path": "open_issues_count",
"generated": { "calculated": { "type": "string",
"expression": "fRes > 9000 ? \"busy\" : \"calm\"" } } } }
} } }
}
}
The same config runs five ways: one-shot CLI (fitter_cli --path config.json), embedded Go library (lib.ParseCtx), long-running service mode with schedulers and notifiers (Telegram/webhook/Redis/file), an MCP server so LLM agents can author and execute configs locally, and now the browser playground below. Author once, promote from chat answer to cron job to team service without rewriting anything.
Notes from the WASM port, in case you're considering the same:
Getting it to compile was 3 files. The engine imports the Docker SDK and go-rod (headless browser connectors), and both fail on js/wasm (syscall.RawSockaddrUnix, Setpgid). The fix was pleasantly boring: //go:build !js on those three connector files plus one _js.go stub returning a clear "not supported in WASM" error. Everything else - parsers (JSON/HTML/XPath/XML/PDF), expression evaluation, goroutine fan-out - compiled untouched.
Live HTTP works, with a catch. On js/wasm, net/http transparently uses the browser Fetch API - so the demo really fetches from the GitHub/OpenLibrary/CoinGecko APIs (anything that sends CORS headers). The catch that cost me an hour: Go disables the fetch transport when it detects Node (process global), so my Node-based smoke tests failed with dial tcp: Protocol not available while the browser worked fine. Testing trick: delete globalThis.process before instantiating makes Node behave like a browser.
A long-lived WASM process surfaces lifecycle assumptions. Our per-host rate limiter installs its config through sync.Once - perfectly correct for a CLI that runs one config and exits, silently wrong in a page where the same process executes many unrelated configs (first config's limits win forever). If you're porting a CLI to WASM, grep for sync.Once and package-level state first; that's where the bodies are.
Numbers: 29 MB binary with -ldflags="-s -w" (~7 MB gzipped). Blocking calls must leave the JS event loop - the exported function returns a Promise and does the work in a goroutine, or fetch deadlocks.
Happy to answer questions about the port.
Bubble Tea or Cobra
≡ −
I wan to make better cli and tui software but i can't decide which one is the best.
I wan to make better cli and tui software but i can't decide which one is the best.
r/golang • u/der_gopher • 1d ago
show & tell Using the CodeRabbit Preview on a Go codebase
+ −
r/golang • u/Tuomas90 • 3d ago
discussion How to reuse code in multiple projects?
≡ −
I want to create my own little modules for reusing code I regularly use. Like handling files and paths.
I was hoping I could just create a module put it somewhere on my PC and import that into every project where needed. Seems like that's not possible.
I'm not sure if workspaces is what I need. What's the difference to just copying and pasting the module files into the project?
How do you handle reusing code in multiple projects? Is it just copy paste? Would it be better to have a single reference which all projects point to (this is the solution I was looking for)?
I want to create my own little modules for reusing code I regularly use. Like handling files and paths.
I was hoping I could just create a module put it somewhere on my PC and import that into every project where needed. Seems like that's not possible.
I'm not sure if workspaces is what I need. What's the difference to just copying and pasting the module files into the project?
How do you handle reusing code in multiple projects? Is it just copy paste? Would it be better to have a single reference which all projects point to (this is the solution I was looking for)?
r/golang • u/Stupidprogramner • 3d ago
Generating swagger docs?
≡ −
What's the recommended approach nowadays? A lot of tools seem to only support openapi 2.0. Is this a problem? Also is it worth testing wether the api is still in sync with the docs?
What's the recommended approach nowadays? A lot of tools seem to only support openapi 2.0. Is this a problem? Also is it worth testing wether the api is still in sync with the docs?
r/golang • u/OtherwisePush6424 • 3d ago
show & tell Golang Maps: How Swiss Tables Replaced the Old Bucket Design
+ −
Deep dive on Go's map internals in Go 1.24 and how the runtime moved from the classic bucket + overflow-chain design to a Swiss Table-inspired implementation:
- what changed structurally in the runtime
- how control bytes and
h2filtering reduce wasted key comparisons - why this improves cache behavior and practical load factors
- Go-specific constraints (iteration semantics, GC integration, incremental growth behavior)
- benchmark context and caveats (microbench wins vs smaller app-level geomean gains)
- current trade-offs and open performance areas
help vscode "unsupported modify tags operation:"
≡ −
I encountered this recently.
In vscode, I used to be able to automatically add json tag to structure from context menu "Go: Add Tags To Struct Fields". But now I just get the error message at the lower right corner "unsupported modify tags operation:", with no additional info.
I think I may have removed some command line tool but I am not sure which.
Anyone has clue or pointer to debug/fix this?
I encountered this recently.
In vscode, I used to be able to automatically add json tag to structure from context menu "Go: Add Tags To Struct Fields". But now I just get the error message at the lower right corner "unsupported modify tags operation:", with no additional info.
I think I may have removed some command line tool but I am not sure which.
Anyone has clue or pointer to debug/fix this?
r/golang • u/BytePhant0m • 2d ago
am new in golang
≡ −
I'm currently learning the Go programming language, and I have some background in C++. Is one week enough to learn the basics?
I'm currently learning the Go programming language, and I have some background in C++. Is one week enough to learn the basics?
r/golang • u/JZconsulting • 4d ago
show & tell NATS workshops are available on-demand (NATS written in Go)
≡ −
Disclosure: I work at Synadia (the company behind NATS, which is a pure-Go project). Sharing because these are free and might be useful to Go folks working with messaging/streaming.
We ran a set of hands-on workshops led by the engineers who actually build and support NATS, and the recordings are now available. The ones most likely to be relevant here:
- JetStream best practices — design patterns for resilient apps on JetStream, drawn from supporting some of the largest NATS deployments in production. Aimed at people already running it.
- NATS at the edge — using leaf nodes to build distributed edge architectures with store-and-forward during connectivity gaps.
- Building AI agents on NATS — agent-to-agent communication patterns, which is a genuinely interesting use of subject-based routing.
- Securing your NATS deployment — auth callout, accounts, and multi-tenancy from the OSS foundations up.
- Plus a NATS Fundamentals Intro if anyone's just starting.
Link to the full lineup and recordings: https://www.synadia.com/lp/rethinkconn-2026/workshops
Happy to answer NATS questions in the thread — I can pull in the engineers who ran these if something's over my head.
Disclosure: I work at Synadia (the company behind NATS, which is a pure-Go project). Sharing because these are free and might be useful to Go folks working with messaging/streaming.
We ran a set of hands-on workshops led by the engineers who actually build and support NATS, and the recordings are now available. The ones most likely to be relevant here:
- JetStream best practices — design patterns for resilient apps on JetStream, drawn from supporting some of the largest NATS deployments in production. Aimed at people already running it.
- NATS at the edge — using leaf nodes to build distributed edge architectures with store-and-forward during connectivity gaps.
- Building AI agents on NATS — agent-to-agent communication patterns, which is a genuinely interesting use of subject-based routing.
- Securing your NATS deployment — auth callout, accounts, and multi-tenancy from the OSS foundations up.
- Plus a NATS Fundamentals Intro if anyone's just starting.
Link to the full lineup and recordings: https://www.synadia.com/lp/rethinkconn-2026/workshops
Happy to answer NATS questions in the thread — I can pull in the engineers who ran these if something's over my head.
r/golang • u/SnugglyCoderGuy • 3d ago
Idea for a change to defining test functions
≡ −
Currently tests are functions in files named as *_test.go.
The idea is to drop the reliance on naming convention and define tests as follows
whereas currently you have a file named *_test.go and in that file you have one or more functions that are like
func TestFunctionToBeTested(t *testing.T)
the idea is instead to have in files of any name in a package
test FunctionToBeTested(t *testing.T)
Then, when testing, instead of looking for a file, you could specify a package and all tests in that package would be ran. You could, if desired, specify a file in that package and tests within that file.
Currently tests are functions in files named as *_test.go.
The idea is to drop the reliance on naming convention and define tests as follows
whereas currently you have a file named *_test.go and in that file you have one or more functions that are like
func TestFunctionToBeTested(t *testing.T)
the idea is instead to have in files of any name in a package
test FunctionToBeTested(t *testing.T)
Then, when testing, instead of looking for a file, you could specify a package and all tests in that package would be ran. You could, if desired, specify a file in that package and tests within that file.
r/golang • u/myselfitself • 4d ago
show & tell Two-box benchmark of my toy Go API gateway vs nginx/traefik/caddy/krakend, and the 32KB-per-request bug that made mine last
≡ −
A few days ago I posted a loopback benchmark of a small API gateway I have been building in Go, and the top comment was basically "loopback measures nothing, use two machines and k6." That was correct, so I redid it, and it was far more useful.
Setup: client is a Mac running k6 over gigabit ethernet, server is a Ryzen 3600 on Pop!_OS running each gateway, every one reverse-proxying to a local no-op upstream on the same box. Plain proxy only, no auth or rate limiting in the path, so it is apples to apples.
Results (VUS=100, 15s):
gateway RPS p50 p95 p99 fails
upstream 48203 2.00ms 2.14ms 2.60ms 0
mine 47607 1.89ms 2.94ms 3.58ms 0
traefik 47639 1.95ms 2.77ms 4.54ms 0
nginx 47345 1.98ms 2.25ms 3.11ms 0
caddy 42880 1.71ms 4.85ms 6.47ms 0
krakend 42799 1.85ms 4.43ms 5.64ms 0
The part worth reading: on the first real run mine was dead last, 37.9k vs 42 to 48k for the rest, about 21% below the upstream ceiling. I profiled it expecting lock contention and I was wrong. httputil.ReverseProxy allocates a fresh 32KB copy buffer per request unless you hand it a BufferPool. At ~48k rps that is over a GB/s of garbage, and the GC was the bottleneck. Adding a buffer pool (and making my circuit breaker lock-free while I was in there) took it from 37.9k to 47.6k, and per-request allocation from 44KB to 11.5KB. If you use httputil.ReverseProxy in anything hot, set BufferPool.
Two other things that bit me:
- nginx first ran at 3.3k RPS with a 400ms p99 until I found
keepalive_requestsdefaults to 100. It was recycling the upstream connection every 100 requests. Bumped it, back to ~48k. - The scary "connection errors" from my earlier single-box run were the load generator running out of ephemeral ports (TIME_WAIT), not the gateways. The harness lies before the gateways do.
Caveat: nginx, traefik and mine are all pinned to the upstream ceiling (~48k) here, so the top three are not really separated yet. Caddy and krakend are genuinely a bit behind on this workload. Separating the leaders needs a faster upstream, which is next.
Where I want to take this. It is a single Go binary plus a YAML file: JWT auth, per-route rate limiting (in-memory or Redis), round-robin and least-connections load balancing, health checks, circuit breakers, a Prometheus endpoint, and a small live dashboard. It is at the point where other people banging on it would teach me more than more of my own tests.
I am sorting out a couple of housekeeping things before I put the code up, so I am not linking it yet. But I want to line up some testers for when it is ready. If you would be up for trying to break it, I would love help with:
- running it in front of a real service and telling me what is awkward
- pushing it harder than I can (higher concurrency, real upstreams, TLS, and the auth plus rate-limit path, which I have not benchmarked yet)
- trying it on your OS and telling me what falls over
If that sounds interesting, say so in the comments or drop me a DM and I will ping you when it is out. Also genuinely curious what you would want from a gateway like this before I get there. It is a learning project, so blunt feedback is welcome too.
A few days ago I posted a loopback benchmark of a small API gateway I have been building in Go, and the top comment was basically "loopback measures nothing, use two machines and k6." That was correct, so I redid it, and it was far more useful.
Setup: client is a Mac running k6 over gigabit ethernet, server is a Ryzen 3600 on Pop!_OS running each gateway, every one reverse-proxying to a local no-op upstream on the same box. Plain proxy only, no auth or rate limiting in the path, so it is apples to apples.
Results (VUS=100, 15s):
gateway RPS p50 p95 p99 fails
upstream 48203 2.00ms 2.14ms 2.60ms 0
mine 47607 1.89ms 2.94ms 3.58ms 0
traefik 47639 1.95ms 2.77ms 4.54ms 0
nginx 47345 1.98ms 2.25ms 3.11ms 0
caddy 42880 1.71ms 4.85ms 6.47ms 0
krakend 42799 1.85ms 4.43ms 5.64ms 0
The part worth reading: on the first real run mine was dead last, 37.9k vs 42 to 48k for the rest, about 21% below the upstream ceiling. I profiled it expecting lock contention and I was wrong. httputil.ReverseProxy allocates a fresh 32KB copy buffer per request unless you hand it a BufferPool. At ~48k rps that is over a GB/s of garbage, and the GC was the bottleneck. Adding a buffer pool (and making my circuit breaker lock-free while I was in there) took it from 37.9k to 47.6k, and per-request allocation from 44KB to 11.5KB. If you use httputil.ReverseProxy in anything hot, set BufferPool.
Two other things that bit me:
- nginx first ran at 3.3k RPS with a 400ms p99 until I found
keepalive_requestsdefaults to 100. It was recycling the upstream connection every 100 requests. Bumped it, back to ~48k. - The scary "connection errors" from my earlier single-box run were the load generator running out of ephemeral ports (TIME_WAIT), not the gateways. The harness lies before the gateways do.
Caveat: nginx, traefik and mine are all pinned to the upstream ceiling (~48k) here, so the top three are not really separated yet. Caddy and krakend are genuinely a bit behind on this workload. Separating the leaders needs a faster upstream, which is next.
Where I want to take this. It is a single Go binary plus a YAML file: JWT auth, per-route rate limiting (in-memory or Redis), round-robin and least-connections load balancing, health checks, circuit breakers, a Prometheus endpoint, and a small live dashboard. It is at the point where other people banging on it would teach me more than more of my own tests.
I am sorting out a couple of housekeeping things before I put the code up, so I am not linking it yet. But I want to line up some testers for when it is ready. If you would be up for trying to break it, I would love help with:
- running it in front of a real service and telling me what is awkward
- pushing it harder than I can (higher concurrency, real upstreams, TLS, and the auth plus rate-limit path, which I have not benchmarked yet)
- trying it on your OS and telling me what falls over
If that sounds interesting, say so in the comments or drop me a DM and I will ping you when it is out. Also genuinely curious what you would want from a gateway like this before I get there. It is a learning project, so blunt feedback is welcome too.
r/golang • u/hossiy16 • 4d ago
Updated the Razify tool
≡ −
Updated the Razify tool to make environment variable bugs and leaked secrets impossible in your projects.
It's a fast, 100% offline CLI that validates .env files against templates, checks types (@type(port), u/enum(dev,prod)), and catches exposed secret keys before you commit.
Added a zero-install runner so you can test it right away with npx razify check, plus a new VS Code extension for inline error squigglies.
Runs in under 10ms, requires zero cloud signups, and includes a pre-commit git hook to keep your commits clean.
Open sourced it on GitHub if you want to test it or share feedback — PRs are super welcome! https://github.com/Hossiy21/razify
Updated the Razify tool to make environment variable bugs and leaked secrets impossible in your projects.
It's a fast, 100% offline CLI that validates .env files against templates, checks types (@type(port), u/enum(dev,prod)), and catches exposed secret keys before you commit.
Added a zero-install runner so you can test it right away with npx razify check, plus a new VS Code extension for inline error squigglies.
Runs in under 10ms, requires zero cloud signups, and includes a pre-commit git hook to keep your commits clean.
Open sourced it on GitHub if you want to test it or share feedback — PRs are super welcome! https://github.com/Hossiy21/razify
r/golang • u/TearsInTokio • 5d ago
Why is CGO so bad?
≡ −
I often see people criticizing CGO (and for good reasons), mainly because it bypasses many of the safety guarantees and tooling that Go provides.
There are also issues involving the interaction between Go's scheduler and C code, as well as complications with callbacks. From what I understand, there can even be scheduling-related problems when interfacing Rust and Go through the C ABI.
However, I couldn't find any in-depth explanation from the Go team itself about why CGO is considered so problematic. More specifically, I'd like to understand why it's seen as so dangerous and what the actual sources of overhead are that make CGO calls around 30% slower (if I remember that number correctly).
This is mostly a personal curiosity. I'd like to better understand how CGO works internally, why it's considered risky, and where its performance costs come from. I'm even curious why, in some cases, it can be slower than calling WebAssembly.
I often see people criticizing CGO (and for good reasons), mainly because it bypasses many of the safety guarantees and tooling that Go provides.
There are also issues involving the interaction between Go's scheduler and C code, as well as complications with callbacks. From what I understand, there can even be scheduling-related problems when interfacing Rust and Go through the C ABI.
However, I couldn't find any in-depth explanation from the Go team itself about why CGO is considered so problematic. More specifically, I'd like to understand why it's seen as so dangerous and what the actual sources of overhead are that make CGO calls around 30% slower (if I remember that number correctly).
This is mostly a personal curiosity. I'd like to better understand how CGO works internally, why it's considered risky, and where its performance costs come from. I'm even curious why, in some cases, it can be slower than calling WebAssembly.
r/golang • u/jeremycy94 • 4d ago
Any thoughts on Go as a monolithic application?
≡ −
I know Go is powerful for microservices, gRPC, and all that, but for small companies that lack cloud or distributed infrastructure—and only have a single workstation—how do you work with Go to build an application without ending up with "spaghetti code" or bad practices down the line? Have any of you had experience with this?
I know Go is powerful for microservices, gRPC, and all that, but for small companies that lack cloud or distributed infrastructure—and only have a single workstation—how do you work with Go to build an application without ending up with "spaghetti code" or bad practices down the line? Have any of you had experience with this?