← Back to blog

Why I Chose Go for BizzFolio's Backend

Mar 19, 20268 min read

When I started building BizzFolio — a photo-first marketplace connecting consumers with local businesses — one of the first decisions was the backend language. I evaluated Node.js, Python, Rust, and Go. I chose Go, and 16 weeks later I'm confident it was the right call.

The Requirements

BizzFolio needed a backend that could handle concurrent photo uploads, real-time feed generation, full-text search, and JWT authentication — all while being deployable as a single binary behind Docker on AWS. Performance mattered because the feed algorithm touches the database on every request, and I needed sub-100ms response times to keep the mobile PWA feeling snappy.

Equally important: I was building this solo. Whatever I picked needed to be productive for a single developer shipping an MVP in 16 weeks. No time for fighting the toolchain.

Why Not Node.js

Node.js was the obvious choice. Massive ecosystem, shared language with the React frontend, easy hiring if the project grows. I've built production Node services before and I know the ecosystem well.

But Node's single-threaded model was a concern. BizzFolio processes photo uploads, generates feed rankings, and runs search queries concurrently. Yes, you can use worker threads or cluster mode, but the concurrency model always feels bolted on rather than native. TypeScript helps with correctness, but the runtime is still JavaScript — and for a CPU-bound feed algorithm, I wanted something faster out of the box.

The dependency tree was the other factor. A typical Express/Fastify project pulls in hundreds of packages. For a production system I'd be maintaining for years, I wanted a smaller surface area.

Why Not Rust

Rust would give me the best performance, full stop. Actix-web benchmarks are untouchable, and the type system catches entire categories of bugs at compile time.

But I had 16 weeks. Rust's learning curve — lifetimes, borrow checker, async runtimes — would have eaten weeks I didn't have. I've written Rust before, but not at the speed I needed for an MVP. The ecosystem for web services (ORMs, auth middleware, etc.) is also less mature than Go's. For a longer-timeline project or a performance-critical system, I'd absolutely consider it.

Why Not Python

Python with FastAPI is excellent for rapid prototyping. Great ecosystem, clean syntax, good async support with asyncio.

The performance gap was the dealbreaker. BizzFolio's feed algorithm does significant computation per request — ranking businesses, filtering by location, applying user preferences. In benchmarks for our specific workload, Go was 5-8x faster than Python. That translates directly to smaller (cheaper) AWS instances and better user experience.

Python also lacks the deployment simplicity of a compiled binary. Dependency management with pip/poetry, Python version issues across environments — I wanted docker build to produce a 15MB container with a single binary.

Why Go Won

Go hit the sweet spot across every dimension that mattered:

Concurrency is native

Goroutines and channels are first-class. Photo upload processing, feed generation, and search indexing run concurrently without callbacks, promises, or thread pool management. The code reads sequentially even when it executes concurrently.

The standard library is production-grade

Go's net/http, encoding/json, crypto, and database/sql packages are solid. I used the Echo framework for routing and middleware, but the dependency tree stayed small. The entire go.sum file is under 100 entries — compare that to a typical package-lock.json.

Compile times are instant

The full BizzFolio backend compiles in under 3 seconds. Hot reload with Air gives a tight development loop. Rust compilation times would have been 10-30x slower for a project this size.

Deployment is trivial

go build produces a statically-linked binary. The production Docker image is 15MB (scratch base). No runtime, no interpreter, no dependency resolution at deploy time. It starts in milliseconds.

Performance is excellent

The feed endpoint — BizzFolio's most complex query — responds in 12-45ms under load. That includes database queries, ranking computation, and JSON serialization. Good enough to never need a caching layer for the MVP, which saved weeks of complexity.

Error handling forces correctness

Go's explicit error handling (if err != nil) gets criticism for verbosity, but it meant every error path in BizzFolio is handled explicitly. No uncaught exceptions in production. No surprise panics. For a solo developer without a QA team, this matters.

The Trade-offs

Go isn't perfect. The lack of generics (until recently) meant some repetitive code for type-safe collection operations. The error handling is verbose. The ecosystem for ORMs is weaker than Node/Python — I used raw SQL with sqlx which was fine but required more boilerplate than something like Prisma or SQLAlchemy.

The biggest trade-off: hiring. If BizzFolio scales and needs more backend developers, the Go talent pool is smaller than Node or Python. But the simplicity of Go means onboarding is fast — a competent developer in any language can be productive in Go within a week.

Results After 16 Weeks

The backend is ~6,000 lines of Go across 40+ files. It handles user auth, photo management, feed generation, full-text search, analytics, and admin operations. Test coverage is over 70%. It runs in a 15MB Docker container and responds to most endpoints in under 50ms.

I shipped on schedule. The language never slowed me down. If anything, Go's simplicity — no magic, no metaprogramming, no framework conventions to memorize — kept me focused on the product instead of the toolchain.

For a solo developer building a production MVP on a deadline, Go was the right choice. Your mileage may vary — but if your requirements look anything like mine, it's worth serious consideration.

Read the full BizzFolio case study →