You're running a Flask server with a trained model. Production load hits. Memory spikes. The GIL locks. You add more pods. Now you're managing Python dependencies across 20 containers.
Go solves the deployment problem Python created. Train in Python (PyTorch, scikit-learn, Jupyter). Deploy in Go (single binary, 10MB RAM, no interpreter). Read Parquet with Apache Arrow. Serve models via ONNX. Ship one file that runs everywhere.
Why Go for Data Science
The Problem Python Solves Well
Python dominates data science with 92% of the ML market (2026). NumPy, pandas, scikit-learn, PyTorch — the ecosystem is mature, documented, and battle-tested. Jupyter notebooks accelerate exploration. Pre-trained models ship with Python APIs.
For training and exploration, Python wins.
The Problem Python Doesn't Solve
You've trained a model in Python. Now you need to serve it:
Deployment: Copy one file. Run it. No interpreter, no packages, no environment.
Performance
Memory footprint: 10-50MB per service
Cold start: <100ms (no import overhead)
Native concurrency: Goroutines handle thousands of concurrent requests
Go is 6x faster than Python on average for CPU-bound tasks (Computer Language Benchmarks Game, 2026). For I/O-bound operations, the gap narrows to 1.4x. For pure computation (inference, numerical processing), the gap reaches 29x.
The Tradeoff
Python has pandas, NumPy, scikit-learn, PyTorch. Go has Gota (less mature than pandas), Gonum (less extensive than NumPy), GoLearn (smaller than scikit-learn).
You don't choose one. You use Python for training, Go for serving. Export models to ONNX. Load them in Go. Ship a single binary.
Quick Win: Deploy a Parquet Reader in 5 Minutes
You have Parquet files in S3. You need to serve aggregated stats via HTTP. Python works, but you're tired of dependency management.
Here's the Go version that compiles to one binary:
go mod init parquet-server
go get github.com/apache/arrow/go/v18/arrow
go get github.com/apache/arrow/go/v18/parquet
go build -o parquet-server
./parquet-server
Docker (10MB image)
FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN CGO_ENABLED=0 go build -o parquet-server
FROM scratch
COPY --from=builder /app/parquet-server /parquet-server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/parquet-server"]
The Python equivalent (Flask + pandas + pyarrow) produces a 600MB image. The Go version is 10MB.
Purpose: pandas-like DataFrame API for data manipulation
Maintenance warning: Gota hasn't been updated in over a year. Evaluate whether this reflects stability or abandonment before using in production.
3. Gonum — Numerical Computing
8,371 stars
Purpose: Linear algebra, statistics, optimization
Use cases: Matrix operations, statistical functions, optimization, plotting
Performance note: Gonum uses pure Go implementations by default. For maximum performance on large matrices, build with CGo-enabled BLAS/LAPACK bindings (adds C dependency).
Purpose: Generate interactive HTML charts (via Apache ECharts)
Chart types: 25+ including line, bar, scatter, heatmap, 3D, geo maps
Use case: Web dashboards served by Go HTTP servers. The output is interactive HTML with JavaScript-powered tooltips and zooming.
Patterns: Production-Ready Data Pipelines
Pattern 1: Train in Python, Serve in Go (via ONNX)
Problem: You need scikit-learn's rich algorithm library but want Go's deployment simplicity.
Solution: Train in Python, export to ONNX, load in Go.
Python side (training)
from sklearn.ensemble import RandomForestClassifier
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
# Train model
X = [[0, 0], [1, 1], [2, 2], [3, 3]]
y = [0, 0, 1, 1]
clf = RandomForestClassifier()
clf.fit(X, y)
# Export to ONNX
initial_type = [('float_input', FloatTensorType([None, 2]))]
onnx_model = convert_sklearn(clf, initial_types=initial_type)
with open("model.onnx", "wb") as f:
f.write(onnx_model.SerializeToString())
Go side (serving)
import (
"encoding/json"
"log"
"net/http"
ort "github.com/yalue/onnxruntime_go"
)
func main() {
ort.SetSharedLibraryPath("onnxruntime.so")
ort.InitializeEnvironment()
defer ort.DestroyEnvironment()
session, _ := ort.NewSession[float32]("model.onnx", nil)
defer session.Destroy()
http.HandleFunc("/predict", func(w http.ResponseWriter, r *http.Request) {
// Parse input, run inference, return result
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
Deployment tradeoff: ONNX Runtime requires libonnxruntime.so as a shared library dependency. This contradicts the "single binary" promise—you'll need the .so file alongside your Go binary. For truly dependency-free deployment, train simpler models and implement inference in pure Go, or export model weights and reimplement the forward pass.
Pattern 2: Parallel Parquet Processing
Problem: Process Parquet files in parallel, aggregate statistics, write results to database.
Solution: Use Apache Arrow for efficient columnar processing, goroutines for parallelism.
See the full guide for complete code examples.
Pattern 3: Real-Time Dashboard with go-echarts
Problem: Build a web dashboard showing live metrics from a time-series database.
Solution: HTTP server in Go, generate charts with go-echarts, serve HTML.
Deployment:
Compile to single binary: go build -o dashboard
Run with systemd: no Python, no dependencies, no virtualenv