Gitea — Structure#
Layout pattern#
Custom layered monolith — not the canonical cmd/internal/pkg layout, but a disciplined three-tier structure: models/ (data), services/ (business logic), routers/ (HTTP). A fourth horizontal layer, modules/, provides cross-cutting utilities. This layout is visible at the top level (not buried under internal/), which is unconventional for a Go project at this size. There is no internal/ package at all; all layering is enforced by convention rather than the Go toolchain.
Directory map#
gitea/
├── main.go # Single binary entry point; delegates to cmd/
├── main_timezones.go # Timezone init (build-tag controlled)
├── Makefile # Primary build system (make build, make frontend, etc.)
├── Dockerfile # Multi-stage: frontend-build → build-env → final image
├── Dockerfile.rootless # Rootless variant for container-security contexts
│
├── cmd/ # CLI command implementations (urfave/cli v3)
│ ├── main.go # NewMainApp: wires all subcommands
│ ├── web.go # `gitea web` — the HTTP server
│ ├── admin*.go # `gitea admin` user/auth/regenerate commands
│ ├── doctor.go # `gitea doctor` — health checks & repair
│ ├── dump.go # `gitea dump` — backup to archive
│ ├── migrate.go # `gitea migrate` — run DB migrations
│ ├── hook.go # `gitea hook` — git hook integration
│ ├── serv.go # `gitea serv` — SSH git service
│ ├── manager.go # `gitea manager` — runtime management via IPC
│ ├── actions.go # `gitea actions` — Actions runner bridge
│ └── ... # cert, keys, generate, docs, config, etc.
│
├── models/ # Data layer: ORM structs + DB queries (xorm)
│ ├── db/ # Core DB primitives (engine, paginator, transactions)
│ ├── migrations/ # Schema versioned migrations (v1_6 → v1_26)
│ ├── fixtures/ # YAML test fixtures (loaded by models/unittest)
│ ├── actions/ # Actions (CI/CD) model
│ ├── auth/ # Authentication tokens, OAuth, sessions
│ ├── git/ # Commit statuses, branches (DB view of git)
│ ├── issues/ # Issues, comments, labels, milestones, reactions
│ ├── migrations/ # DB migration history
│ ├── organization/ # Orgs, teams, team members
│ ├── packages/ # Package registry (with per-type subdirs)
│ │ ├── alpine/ arch/ conan/ conda/ container/ cran/ debian/ nuget/ rpm/
│ ├── perm/access/ # ACL and permission checks
│ ├── pull/ # Pull request model
│ ├── repo/ # Repository model
│ ├── user/ # User model
│ ├── webhook/ # Webhook model
│ └── unittest/ # Test helpers: fixture loading, in-memory DB
│
├── modules/ # Utility/infrastructure layer (no models imports)
│ ├── setting/ # Config loading from app.ini + env
│ ├── log/ # Custom leveled logger
│ ├── git/ # Low-level git command wrappers
│ ├── gitrepo/ # Higher-level git repo operations
│ ├── markup/ # Markdown, orgmode, asciicast, CSV rendering
│ ├── indexer/ # Bleve/Elasticsearch/Meilisearch search
│ ├── web/ # Chi-based HTTP middleware & context helpers
│ ├── queue/ # Async job queue (Redis or in-memory)
│ ├── cache/ # Caching (Redis / in-process)
│ ├── graceful/ # Graceful shutdown infrastructure
│ ├── storage/ # Pluggable file storage (local, S3, MinIO)
│ ├── lfs/ # Git LFS protocol implementation
│ ├── migration/ # Migration framework + bindata migrations
│ ├── auth/ # Auth protocol helpers (OAuth, LDAP, SAML forms)
│ ├── session/ # HTTP session management
│ ├── templates/ # Template loading + bindata
│ ├── public/ # Static asset serving + bindata
│ ├── options/ # Embedded options files + bindata
│ ├── ssh/ # SSH server for git-over-ssh
│ ├── process/ # Process manager for long-running operations
│ └── ... # 50+ additional utility packages
│
├── services/ # Business logic layer (calls models + modules)
│ ├── context/ # Request context (wraps chi ctx with Gitea data)
│ ├── auth/ # Authentication pipeline (sources, sessions, tokens)
│ ├── repository/ # Repository lifecycle (create, fork, delete, mirror)
│ ├── pull/ # PR merge, conflict detection, review
│ ├── issue/ # Issue creation, assignment, notification triggers
│ ├── git/ # Higher-level git operations (push, tag, commit)
│ ├── actions/ # Gitea Actions workflow execution
│ ├── packages/ # Package registry business logic
│ ├── mailer/ # Email rendering + sending
│ ├── webhook/ # Webhook delivery
│ ├── migrations/ # Repository import from GitHub/GitLab/etc.
│ ├── indexer/ # Search indexer coordination
│ ├── cron/ # Cron job definitions (mirrors, cleanup, etc.)
│ ├── convert/ # Model → API DTO conversion
│ ├── forms/ # Web form validation structs
│ └── ... # 30+ service packages
│
├── routers/ # HTTP handler layer (calls services)
│ ├── web/ # HTML web UI handlers (chi router)
│ │ ├── admin/ # Admin panel routes
│ │ ├── auth/ # Sign-in/sign-up/OAuth flow
│ │ ├── repo/ # Repository views (code, issues, PRs, releases, wiki)
│ │ ├── org/ # Organization management
│ │ ├── user/ # User profile, settings, dashboard
│ │ ├── explore/ # Explore pages (repos, users, topics)
│ │ └── ...
│ ├── api/ # REST API handlers
│ │ ├── v1/ # Swagger-annotated API v1 handlers
│ │ ├── actions/ # Actions runner API (GHES-compatible)
│ │ └── packages/ # Package registry API endpoints
│ ├── private/ # Internal inter-process API (hook ↔ web)
│ ├── install/ # First-run installation wizard
│ └── common/ # Shared handler utilities
│
├── templates/ # Go html/template files (server-side rendered)
│ ├── base/ # Layout, header, footer partials
│ ├── repo/ # Repository view templates
│ ├── admin/ org/ user/ # Domain-specific templates
│ └── mail/ # Email templates
│
├── web_src/ # Frontend source (TypeScript + CSS)
│ ├── js/ # TypeScript application code
│ ├── css/ # CSS/Tailwind styles
│ ├── fomantic/ # Fomantic UI (Semantic UI fork) customizations
│ └── svg/ # SVG icon sources
│
├── public/ # Compiled static assets (output of `make frontend`)
│ └── assets/ # JS, CSS bundles + vite manifest
│
├── options/ # Embedded data files
│ ├── locale/ # i18n translation files
│ ├── gitignore/ # Gitignore templates for new repos
│ ├── license/ # License text templates
│ └── label/ # Default label sets
│
├── assets/ # Additional embedded assets (favicons, etc.)
│
├── tests/ # Test infrastructure
│ ├── integration/ # Integration tests (real HTTP + DB)
│ ├── e2e/ # Playwright end-to-end tests
│ ├── fuzz/ # Go fuzz corpus
│ └── testdata/ # Test fixture data
│
├── contrib/ # Operating system service configs
│ ├── systemd/ # systemd unit files
│ ├── init/ # SysV/OpenRC init scripts
│ └── supervisor/ # Supervisor configs
│
├── docker/ # Docker entrypoint scripts
│ ├── root/ # Standard image entrypoints
│ └── rootless/ # Rootless image entrypoints
│
└── build/ # Build helper scripts (go generate, licenses)Entry points#
There is a single binary: gitea, built from main.go at the repository root. All subcommands are in the cmd/ package. Default command (when no subcommand is given) is web.
| Subcommand | Purpose |
|---|---|
gitea web | Starts the HTTP/HTTPS server and SSH server |
gitea admin | Administrative management (users, auth sources, regenerate tokens) |
gitea serv | Invoked by SSH authorized_keys for git-over-SSH |
gitea hook | Git hook integration (pre-receive, post-receive, update) |
gitea doctor | Diagnose and repair Gitea installation issues |
gitea dump | Archive the full Gitea data (DB + repos + attachments) |
gitea migrate | Run pending DB schema migrations |
gitea manager | Runtime manager: flush queues, reload config, GC, logging |
gitea actions | Bridge to Gitea Actions runner protocol |
gitea migrate-storage | Migrate file storage between backends |
gitea dump-repo / restore-repo | Import/export individual repositories |
gitea generate | Generate secrets (internal tokens, JWT signing keys) |
gitea cert | Generate TLS certificates for HTTPS |
gitea docs | Print CLI help as Markdown docs |
gitea config | Display or set config values |
Package organization#
models/— data layer: All xorm ORM structs and DB queries. Packages map directly to domain entities:repo,user,issues,pull,actions,packages,organization,auth,webhook. Thedbsubpackage owns the xorm engine, transaction helpers, and generic paging.migrations/has one subdirectory per minor release (v1_6…v1_26) for schema changes.modules/— infrastructure/utilities: Cross-cutting concerns with no upward imports. Key packages:setting(config),log(logging),git(git subprocess wrappers),markup(render pipeline),queue(async jobs),cache,storage(pluggable backends),graceful(shutdown),indexer(search). Also contains four bindata packages (migration,public,options,templates) that embed files into the binary whenTAGS=bindata.services/— business logic: Orchestrates betweenmodelsandmodules. Each service package corresponds to a feature area:repository,pull,issue,actions,packages,auth,mailer,webhook,migrations(import/migration from other platforms).services/contextprovides the per-request context struct that carries user, repo, and org identity into HTTP handlers.routers/— HTTP handlers: Split intoweb/(HTML UI),api/v1/(REST),api/actions/(Actions runner protocol),api/packages/(package registry),private/(internal IPC), andinstall/(setup wizard). Handlers callservices/— they do not importmodels/directly.Layering summary:
routers→services→models/modules. Themoduleslayer does not importmodelsorservices.modelsdoes not importservicesorrouters. This is a strict downward DAG by convention.
Build system#
- Build tool: GNU Make (
Makefileat root), plus pnpm for the frontend. - Key targets:
make build— compiles bothfrontend(Vite/TypeScript) andbackend(Go binary)make frontend— runspnpm exec vite build; outputs topublic/assets/make backend— runsgo generatethengo build; produces./giteamake generate-backend— runs go generate for bindata embedding and swagger specmake test-backend/make test-frontend— unit testsmake lint-go/make lint-js/make lint-css— lint targetsmake clean— removes binary and generated bindata files
- Asset embedding:
TAGS=bindatatriggers generation ofbindata.*files inmodules/public,modules/options,modules/templates,modules/migration. Without bindata, assets are served from disk. - Frontend stack: TypeScript with Vite bundler, pnpm package manager, Tailwind CSS, Fomantic UI, Vitest for frontend unit tests.
- Docker: Yes, multi-stage.
Dockerfilehas three stages:frontend-build(node/pnpm) — builds JS/CSS assetsbuild-env(golang:alpine) — compiles the Go binary withTAGS="bindata timetzdata sqlite sqlite_unlock_notify"- Final minimal Alpine image with the single
giteabinary
- A separate
Dockerfile.rootlessproduces a rootless OCI image.
- Cross-compilation: Uses
xgofor cross-platform binaries (Linux/Windows/macOS, amd64/arm64/etc.).
Notable structural decisions#
No
internal/boundary. All four main layers (models/,modules/,services/,routers/) are top-level, public packages. Layering is enforced by team convention and linters rather than the Go toolchain. This makes the codebase accessible to contributors but relies on discipline for import discipline.Single binary for all roles. The same
giteabinary serves the web UI, REST API, SSH git service, Actions runner bridge, and all admin CLI operations. Subcommand dispatch viaurfave/cliv3 replaces the more common cobra pattern seen in other large Go projects.Four parallel bindata packages. Static assets, locales, templates, and migration SQL are compiled into the binary when
TAGS=bindata, enabling zero-dependency deployment. The same code also supports disk-based serving (used in development), and the two paths are unified via themodules/assetfsabstraction.Versioned migration subdirectories.
models/migrations/v1_6throughv1_26track every schema change since the project’s inception. Each minor release gets its own package, providing a clear changelog of DB changes and making bisect/debugging straightforward.Separate
private/router for inter-process IPC. The hook process (gitea hook) communicates with the running web server over an internal HTTP API defined inrouters/private/. This avoids shell-out or filesystem IPC for hook→web communication, and keeps the internal surface separate from both the public REST API and the web UI.Hybrid SSR + SPA frontend.
templates/are Gohtml/templatefiles rendered server-side, whileweb_src/is a TypeScript SPA layer built with Vite. The result is server-rendered pages progressively enhanced with JavaScript — a deliberate hybrid avoiding full SPA complexity while still delivering rich interactions.