# Gitea Architecture Explained: Key Modules and System Design

> Explore the Gitea architecture and its key modules. Understand how web routing, Git operations, services, and interface layers work together for efficient code management.

- Repository: [Gitea/gitea](https://github.com/go-gitea/gitea)
- Tags: architecture
- Published: 2026-03-07

---

**Gitea is a modular Go application that separates HTTP routing (`modules/web`), Git operations (`modules/git`), business logic (`services/`), and interface layers (`routers/`), with clear boundaries between web UI, JSON API, and core infrastructure.**

The open-source Git service Gitea (go-gitea/gitea) follows a domain-driven, modular architecture written in Go. Understanding its key modules helps developers extend functionality, debug issues, or contribute to the core platform. The codebase organizes functionality into distinct packages with specific responsibilities, from HTTP request handling in `modules/web` to low-level Git binary interactions in `modules/git`.

## Core HTTP Routing and Interface Layer

### modules/web - The Router Engine

Located in [`modules/web/router.go`](https://github.com/go-gitea/gitea/blob/main/modules/web/router.go), this package provides a thin wrapper around the **chi** router. The `web.NewRouter()` function creates the foundational routing instance used throughout the application, while `web.Use()` registers global middleware chains for authentication, CSRF protection, CORS, and gzip compression.

The core `Router` struct and initialization logic occupy lines 42-78 of [`router.go`](https://github.com/go-gitea/gitea/blob/main/router.go), establishing the entry point for all HTTP traffic. Route registration uses methods like `Get()`, `Post()`, and `Group()` to organize endpoints.

```go
package main

import (
    "net/http"

    "code.gitea.io/gitea/modules/web"
)

func main() {
    // Create a new router
    r := web.NewRouter()

    // Register a GET handler at /hello
    r.Get("/hello", func(ctx *web.Context) {
        ctx.Resp.WriteHeader(http.StatusOK)
        ctx.Resp.Write([]byte("👋 Hello from Gitea!"))
    })

    // Start the HTTP server (normally done by the web server wrapper)
    http.ListenAndServe(":3000", r)
}

```

You can add custom middleware using `r.Use()` as implemented in the source:

```go
package main

import (
    "net/http"

    "code.gitea.io/gitea/modules/web"
)

// Simple logger middleware
func requestID(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Request-ID", "abc123")
        next.ServeHTTP(w, r)
    })
}

func main() {
    r := web.NewRouter()
    // Apply middleware globally
    r.Use(requestID)

    r.Get("/", func(ctx *web.Context) {
        ctx.Resp.Write([]byte("root"))
    })
    http.ListenAndServe(":3000", r)
}

```

### routers/web - Web UI Route Handlers

The `routers/web` package contains all HTML-generating endpoints. The [`routers/web/web.go`](https://github.com/go-gitea/gitea/blob/main/routers/web/web.go) file defines `Routes()` around lines 59-115, which registers every user-facing page including repository views, issue trackers, and admin panels. These handlers render templates and utilize the services layer for business operations.

### routers/api - JSON API Endpoints

REST API routes live in [`routers/api/v1/api.go`](https://github.com/go-gitea/gitea/blob/main/routers/api/v1/api.go), with the entry point `Routes()` around lines 872-904. These handlers return JSON structures defined in `modules/structs`, maintaining strict separation between internal database models and public API contracts.

## Git Operations and Repository Management

### modules/git - Git Plumbing

This module in [`modules/git/git.go`](https://github.com/go-gitea/gitea/blob/main/modules/git/git.go) centralizes all interaction with the underlying `git` binary. Originally an external dependency (`code.gitea/git`), it now lives in-tree and handles repository initialization, fetch/push operations, submodule management, and low-level Git object manipulation. Both UI and API layers delegate Git-specific tasks here rather than calling the binary directly.

### services/repository - High-Level Repository Actions

Business logic for repository lifecycle operations resides in `services/repository/`, including [`fork.go`](https://github.com/go-gitea/gitea/blob/main/fork.go) for forking, transfer, creation, and migration logic. The `repo_service.Fork()` function (lines 1-30) provides a concrete example of how services orchestrate database updates, Git operations, and permission checks.

```go
package main

import (
    "fmt"

    repo_service "code.gitea.io/gitea/services/repository"
    repo_model   "code.gitea.io/gitea/models/repo"
)

func forkDemo(original *repo_model.Repository, userID int64) {
    // repo_service.Fork creates a new fork for the given user
    fork, err := repo_service.Fork(original, userID)
    if err != nil {
        fmt.Printf("fork failed: %v\n", err)
        return
    }
    fmt.Printf("new fork created at %s\n", fork.HTMLURL())
}

```

## Configuration, Logging, and Infrastructure

### modules/setting - Global Configuration

The [`modules/setting/setting.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/setting.go) file loads [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) configuration at startup via `setting.LoadCommonSettings()` and stores runtime values including `AppVer`, `RunMode`, service options, and OAuth2 settings. All other packages import this module to access configuration, ensuring centralized management of deployment parameters.

### modules/log - Structured Logging

Defined in [`modules/log/log.go`](https://github.com/go-gitea/gitea/blob/main/modules/log/log.go), this module initializes loggers that write to console, file, or syslog. The logger initializes in `main.init()` and flushes on shutdown. Every package uses `log.Info()` and `log.Error()` for consistent, structured output across the application.

### modules/graceful - Server Lifecycle

Located in [`modules/graceful/server.go`](https://github.com/go-gitea/gitea/blob/main/modules/graceful/server.go), this module manages graceful shutdown and restart procedures. It ensures in-flight HTTP requests complete before the process exits, preventing data corruption during deployments.

### modules/util - Common Utilities

The [`modules/util/util.go`](https://github.com/go-gitea/gitea/blob/main/modules/util/util.go) package provides shared helper functions for string manipulation, file path operations, and time conversions. This keeps domain-specific modules focused on their primary responsibilities without utility clutter.

### modules/structs - API Data Models

Public data structures for API responses live in `modules/structs/` (e.g., [`user.go`](https://github.com/go-gitea/gitea/blob/main/user.go)). These structs define JSON schemas for entities like `User`, `Repository`, and `Issue`, decoupling internal database models from external API contracts.

## Authentication and Notification Services

### services/auth - Authentication Framework

The `services/auth/` directory implements pluggable authentication methods through the `Method` interface. Files like [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go) (lines 5-26) support OAuth2, HTTP basic auth, reverse-proxy authentication, and session-based login. Router middleware uses this framework to protect routes and identify users according to the source code in `go-gitea/gitea`.

### services/notify - Event Distribution

When repository events occur (new pull requests, issue comments), [`services/notify/notify.go`](https://github.com/go-gitea/gitea/blob/main/services/notify/notify.go) triggers email delivery, webhooks, and internal notifications. This service acts as the event bus for asynchronous side effects, keeping handlers focused on request processing.

## Application Startup and Request Flow

The Gitea architecture follows a clear initialization sequence defined in [`main.go`](https://github.com/go-gitea/gitea/blob/main/main.go):

1. **Configuration Loading**: `setting.InitCfgProvider` parses [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) and establishes global settings.
2. **Router Initialization**: `web.NewRouter()` creates the chi-based router instance.
3. **Route Registration**: The router passes to `routers/web.Routes()` for HTML endpoints and `routers/api/v1.Routes()` for JSON endpoints.
4. **Middleware Application**: `web.Use()` attaches authentication, CSRF, gzip, and logging middleware to route groups.
5. **Request Handling**: UI handlers in `routers/web/*` and API handlers in `routers/api/*` call service layers (`services/repository`, `services/notify`) which delegate Git operations to `modules/git`.
6. **Persistence**: Database models in `models/*` wrap XORM structs, though higher-level code prefers service layers to isolate database specifics from HTTP handlers.

## Summary

- **HTTP Layer**: `modules/web` wraps chi routing, while `routers/web` and `routers/api` handle UI and API endpoints respectively.
- **Git Operations**: `modules/git` provides the sole interface to Git binaries, used by service layers for repository management.
- **Business Logic**: `services/` packages (auth, repository, notify) contain domain logic consumed by both UI and API.
- **Infrastructure**: `modules/setting`, `modules/log`, and `modules/graceful` handle configuration, observability, and lifecycle management.
- **Data Contracts**: `modules/structs` defines public API schemas, maintaining clean separation between internal models and external interfaces.

## Frequently Asked Questions

### What router does Gitea use under the hood?

Gitea uses the **chi** router, wrapped by the internal `modules/web` package. The `web.NewRouter()` function in [`modules/web/router.go`](https://github.com/go-gitea/gitea/blob/main/modules/web/router.go) creates the router instance, and `web.Use()` registers middleware like authentication and CSRF protection.

### Where is the main entry point for Gitea's HTTP server?

The primary HTTP routing setup occurs in [`routers/web/web.go`](https://github.com/go-gitea/gitea/blob/main/routers/web/web.go) for the UI and [`routers/api/v1/api.go`](https://github.com/go-gitea/gitea/blob/main/routers/api/v1/api.go) for the API. Both are initialized from [`main.go`](https://github.com/go-gitea/gitea/blob/main/main.go), which loads configuration via `setting.InitCfgProvider` before starting the server.

### How does Gitea handle Git operations without libgit2?

Gitea calls the native `git` binary directly through the abstraction layer in [`modules/git/git.go`](https://github.com/go-gitea/gitea/blob/main/modules/git/git.go). This module handles all repository initialization, cloning, pushing, and submodule operations as external process calls rather than using libgit2 bindings.

### What is the difference between services and modules in Gitea?

**Modules** (`modules/`) provide low-level infrastructure utilities (routing, logging, Git binary interaction, configuration). **Services** (`services/`) contain high-level business logic like repository forking ([`services/repository/fork.go`](https://github.com/go-gitea/gitea/blob/main/services/repository/fork.go)) and authentication (`services/auth/`) that coordinate multiple modules to fulfill user actions.