Gogs — Structure#

Layout pattern#

Standard Go Layout (cmd/internal), no pkg/

Gogs uses the canonical cmd/ + internal/ layout with no public pkg/ directory — all application code is encapsulated under internal/. This reflects a deliberate decision that Gogs is an application, not a library, with no intent to expose importable packages to external consumers. The layout is straightforward: one binary, one cmd subdirectory, one large internal tree.

Directory map#

gogs/
├── cmd/gogs/           # Single binary entry point; 9 files, 7 subcommands
├── conf/               # Embedded config assets: locales (31 langs), gitignore templates,
│   ├── auth.d/         #   auth source templates
│   ├── gitignore/      #   .gitignore templates for new repos
│   ├── label/          #   default issue label sets
│   ├── license/        #   license templates
│   ├── locale/         #   i18n translation files
│   └── readme/         #   readme templates
├── docker/             # Docker build + runtime + s6 supervisor config (current)
├── docker-next/        # Next-generation Docker setup (in progress)
├── docs/               # User-facing documentation (markdown)
├── internal/           # All application code (288 .go files)
│   ├── app/            # Application-level utilities (metrics, ipynb sanitization)
│   ├── auth/           # Authentication providers
│   │   ├── github/     #   GitHub OAuth
│   │   ├── ldap/       #   LDAP/AD
│   │   ├── pam/        #   PAM
│   │   └── smtp/       #   SMTP auth
│   ├── authx/          # Auth domain extensions (token validation, etc.)
│   ├── avatar/         # Avatar fetching and storage
│   ├── conf/           # Configuration loading (INI-based, with testdata)
│   ├── context/        # HTTP request context; Macaron middleware
│   ├── cron/           # Scheduled background jobs
│   ├── cryptox/        # Cryptographic utilities
│   ├── database/       # Data access layer: models + store (with migrations, schemadoc)
│   │   ├── migrations/ #   schema migration history
│   │   ├── schemadoc/  #   auto-generated schema documentation
│   │   └── testdata/   #   test fixtures including backup snapshots
│   ├── dbtest/         # Database test helpers (shared test infrastructure)
│   ├── dbx/            # Low-level database connection utilities
│   ├── email/          # Email composition and delivery
│   ├── errx/           # Error type utilities
│   ├── form/           # Request form structs (binding targets)
│   ├── gitx/           # Git operation utilities
│   ├── httplib/        # HTTP client utilities
│   ├── iox/            # I/O utilities
│   ├── lazyregexp/     # Lazily-compiled regular expressions
│   ├── lfsx/           # Git LFS utilities
│   ├── markup/         # Content rendering (Markdown, highlight)
│   ├── mocks/          # Test mock implementations
│   ├── netx/           # Network utilities
│   ├── osx/            # OS/filesystem utilities
│   ├── pathx/          # Path manipulation utilities
│   ├── process/        # OS process management (for git subprocess calls)
│   ├── repox/          # Repository-domain utilities
│   ├── route/          # HTTP handler functions (82 .go files total)
│   │   ├── admin/      #   Admin UI handlers
│   │   ├── api/v1/     #   REST API v1 handlers
│   │   ├── dev/        #   Dev-mode template preview
│   │   ├── lfs/        #   Git LFS protocol handlers
│   │   ├── org/        #   Organization handlers
│   │   ├── repo/       #   Repository handlers (61 files — largest subpackage)
│   │   └── user/       #   User handlers
│   ├── semverx/        # Semver comparison utilities
│   ├── ssh/            # Built-in SSH server
│   ├── strx/           # String utilities
│   ├── sync/           # Synchronization primitives
│   ├── template/       # HTML template helper functions + syntax highlighting
│   ├── testx/          # General test utilities
│   ├── tool/           # Miscellaneous utilities
│   ├── urlx/           # URL utilities
│   └── userx/          # User-domain utilities
├── public/             # Static web assets (CSS, JS, images, plugins) — embedded
├── scripts/            # Service manager configs: systemd, launchd, supervisor, Windows
└── templates/          # HTML templates (Macaron renderer) — embedded

Entry points#

Single binary with multiple subcommands (urfave/cli v3):

CommandFilePurpose
gogs webcmd/gogs/web.goStart the full web server (HTTP/HTTPS/FCGI/Unix socket)
gogs servcmd/gogs/serv.goSSH git-serve hook (called by sshd for each git push/pull)
gogs hookcmd/gogs/hook.goGit server-side hooks (pre-receive, post-receive, update)
gogs admincmd/gogs/admin.goAdmin CLI utilities (create user, etc.)
gogs importcmd/gogs/import.goImport repositories from local disk
gogs backupcmd/gogs/backup.goCreate a backup archive
gogs restorecmd/gogs/restore.goRestore from a backup archive

The web server and SSH server are both part of a single binary; gogs serv is invoked as an authorized_keys command by OpenSSH.

Package organization#

  • Internal packages: Everything lives under internal/; no public packages exist. Key groupings:

    • internal/database — the central data layer; contains all model types and store implementations
    • internal/route/* — HTTP handler tree organized by domain (user, repo, org, admin, api)
    • internal/conf — INI-file configuration with typed config structs
    • internal/context — Macaron middleware providing the *context.Context request object
    • internal/auth/* — Pluggable authentication backends
    • internal/*x — A family of utility packages following an x-suffix naming convention (iox, strx, osx, urlx, errx, netx, pathx, repox, dbx, lfsx, gitx, cryptox, authx, semverx, userx)
  • Public packages (pkg/): None. This is a pure application.

  • Layering: Loosely layered but not strictly enforced:

    • cmd/internal/route/* (HTTP handlers) → internal/database (data access) → DB
    • internal/context acts as horizontal glue; most route handlers accept *context.Context
    • No formal service layer; route handlers interact with internal/database directly (thin-controller style)
    • internal/app provides cross-cutting application concerns (metrics, security)

Build system#

  • Build tool: task (Taskfile.yml) — a modern Make alternative
  • Key targets:
    • task build — compiles ./cmd/gogs to .bin/gogs with ldflags for build time/commit and optional build tags (e.g., TAGS="cert pam")
    • task web — builds and starts the web server
    • task generate — runs go generate ./...
    • task generate-schemadoc — regenerates database schema documentation
    • task lint — runs linter
  • Docker: Yes, multi-stage. Dockerfile uses golang:1.26-alpine builder stage running task build, then an alpine:3.23 runtime stage with s6 process supervisor. A separate Dockerfile.next and docker-next/ directory indicate a Docker setup migration in progress.

Notable structural decisions#

  1. x-suffix utility package convention: Gogs has a distinctive pattern of naming utility packages with an x suffix (iox, strx, osx, urlx, etc.) to avoid collisions with stdlib packages (os, io, strings). This naming is consistent across ~15 packages and makes the internal/stdlib boundary visually clear.

  2. Route registration in cmd/gogs/web.go: The entire route tree (700+ lines) lives in the binary’s entry file rather than in a dedicated router file within internal/route. This collocates the HTTP topology with the server startup logic but makes web.go a very large file. All handler functions themselves are in internal/route/*.

  3. No service layer: Route handlers call internal/database store functions directly. There is no intermediate service/domain layer separating HTTP concerns from business logic. This keeps the structure flat but blurs concerns in handlers.

  4. Embedded assets (Go embed): Both public/ (static files) and templates/ (HTML templates) are embedded into the binary via go:embed, allowing true single-binary deployment. A conf.Server.LoadAssetsFromDisk flag exists for development to reload from disk without rebuilding.

  5. internal/database dominance: With 61 source files and direct access from route handlers, the database package is the largest and most central package. It contains both model structs and store operations, acting as both a domain model and a repository layer.

  6. Dual Docker setup: The presence of both docker/ and docker-next/ signals an ongoing infrastructure migration. The .next variant likely represents a modernized Docker configuration that hasn’t replaced the original yet.