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.

SubcommandPurpose
gitea webStarts the HTTP/HTTPS server and SSH server
gitea adminAdministrative management (users, auth sources, regenerate tokens)
gitea servInvoked by SSH authorized_keys for git-over-SSH
gitea hookGit hook integration (pre-receive, post-receive, update)
gitea doctorDiagnose and repair Gitea installation issues
gitea dumpArchive the full Gitea data (DB + repos + attachments)
gitea migrateRun pending DB schema migrations
gitea managerRuntime manager: flush queues, reload config, GC, logging
gitea actionsBridge to Gitea Actions runner protocol
gitea migrate-storageMigrate file storage between backends
gitea dump-repo / restore-repoImport/export individual repositories
gitea generateGenerate secrets (internal tokens, JWT signing keys)
gitea certGenerate TLS certificates for HTTPS
gitea docsPrint CLI help as Markdown docs
gitea configDisplay 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. The db subpackage owns the xorm engine, transaction helpers, and generic paging. migrations/ has one subdirectory per minor release (v1_6v1_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 when TAGS=bindata.

  • services/ — business logic: Orchestrates between models and modules. Each service package corresponds to a feature area: repository, pull, issue, actions, packages, auth, mailer, webhook, migrations (import/migration from other platforms). services/context provides the per-request context struct that carries user, repo, and org identity into HTTP handlers.

  • routers/ — HTTP handlers: Split into web/ (HTML UI), api/v1/ (REST), api/actions/ (Actions runner protocol), api/packages/ (package registry), private/ (internal IPC), and install/ (setup wizard). Handlers call services/ — they do not import models/ directly.

  • Layering summary: routersservicesmodels/modules. The modules layer does not import models or services. models does not import services or routers. This is a strict downward DAG by convention.

Build system#

  • Build tool: GNU Make (Makefile at root), plus pnpm for the frontend.
  • Key targets:
    • make build — compiles both frontend (Vite/TypeScript) and backend (Go binary)
    • make frontend — runs pnpm exec vite build; outputs to public/assets/
    • make backend — runs go generate then go build; produces ./gitea
    • make generate-backend — runs go generate for bindata embedding and swagger spec
    • make test-backend / make test-frontend — unit tests
    • make lint-go / make lint-js / make lint-css — lint targets
    • make clean — removes binary and generated bindata files
  • Asset embedding: TAGS=bindata triggers generation of bindata.* files in modules/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. Dockerfile has three stages:
    1. frontend-build (node/pnpm) — builds JS/CSS assets
    2. build-env (golang:alpine) — compiles the Go binary with TAGS="bindata timetzdata sqlite sqlite_unlock_notify"
    3. Final minimal Alpine image with the single gitea binary
    • A separate Dockerfile.rootless produces a rootless OCI image.
  • Cross-compilation: Uses xgo for cross-platform binaries (Linux/Windows/macOS, amd64/arm64/etc.).

Notable structural decisions#

  1. 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.

  2. Single binary for all roles. The same gitea binary serves the web UI, REST API, SSH git service, Actions runner bridge, and all admin CLI operations. Subcommand dispatch via urfave/cli v3 replaces the more common cobra pattern seen in other large Go projects.

  3. 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 the modules/assetfs abstraction.

  4. Versioned migration subdirectories. models/migrations/v1_6 through v1_26 track 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.

  5. Separate private/ router for inter-process IPC. The hook process (gitea hook) communicates with the running web server over an internal HTTP API defined in routers/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.

  6. Hybrid SSR + SPA frontend. templates/ are Go html/template files rendered server-side, while web_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.