← Home | Blog

Building January: A Batteries-Included Go Framework

15 Jan 2025

2 min read

Author icon

Akshansh Gusain


Why Another Web Framework?

When I started building January, the Go ecosystem had plenty of great web frameworks. Gin, Echo, Fiber - all excellent choices. But coming from a Django background, I missed the “batteries-included” philosophy that made Python web development so productive.

Go frameworks typically give you routing and middleware, leaving you to figure out the rest. I wanted something different - a framework that provides structure, conventions, and common functionality out of the box, while still feeling like idiomatic Go.


Design Principles

Convention Over Configuration

Django taught me the power of sensible defaults. Instead of requiring developers to wire up every component manually, January assumes you want:

  • Database connections with connection pooling
  • Template rendering with hot reloading in development
  • CSRF protection enabled by default
  • Structured logging out of the box

You can override any of these, but the defaults get you building features immediately.

Keep It Go

Despite drawing inspiration from Django, January doesn’t try to be Django in Go syntax. It embraces Go’s strengths:

// Routes are defined using standard Go patterns
app.Route("GET /users/{id}", handlers.GetUser)

// Middleware is just a function
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Authentication logic
        next.ServeHTTP(w, r)
    })
}

The ORM Challenge

One of the most challenging aspects was designing the ORM. Go lacks the runtime reflection capabilities that make Django’s ORM so magical. After experimenting with several approaches, I settled on a code generation strategy:

type User struct {
    ID        int       `january:"primary_key"`
    Email     string    `january:"unique"`
    CreatedAt time.Time `january:"auto_now_add"`
}

// Generated query methods
users, err := User.Objects.Filter("email__contains", "@example.com").All()

The generator creates type-safe query methods at build time, giving you Django-like ergonomics with Go’s compile-time guarantees.


What’s Next

January is still evolving. Current focus areas include:

  • Admin Interface: Auto-generated CRUD admin panel
  • Migrations: Schema versioning and rollback support
  • Testing Utilities: Factory fixtures and integration test helpers

If you’re interested in contributing or just want to try it out, check out the January repository.