Open-Source Wikis

/

GitLab

/

GitLab

/

Architecture

gitlab-org/gitlab

Architecture

GitLab is a Rails monolith plus a small constellation of helper services. The monolith is the source of truth for application logic; everything else exists to make the monolith fast, durable, or scalable.

High-level request flow

graph LR
    User[User browser / git client / CI runner]
    LB[Load balancer / NGINX]
    WH[Workhorse - Go]
    Puma[Puma - Rails 7.2]
    Sidekiq[Sidekiq workers]
    PG[(PostgreSQL<br/>main + ci + sec)]
    Redis[(Redis<br/>cache, queues, sessions)]
    Gitaly[Gitaly gRPC]
    OS[(Object storage<br/>S3 / GCS)]
    ES[(Elasticsearch / Zoekt)]
    CH[(ClickHouse)]

    User --> LB
    LB --> WH
    WH -->|fast paths<br/>uploads/downloads/git| OS
    WH -->|cached static| WH
    WH -->|other| Puma
    Puma --> PG
    Puma --> Redis
    Puma --> Gitaly
    Puma -->|enqueue| Sidekiq
    Sidekiq --> PG
    Sidekiq --> Redis
    Sidekiq --> Gitaly
    Sidekiq --> ES
    Puma --> ES
    Puma --> CH

The seven runtime components

Component Process Source location Role
Workhorse Go binary workhorse/ Reverse proxy, file uploads, git over HTTP, websockets, image resizing
Puma Ruby web server config/puma.rb.example, app/, lib/, ee/app/, ee/lib/ Serves HTML, REST, GraphQL
Sidekiq Ruby worker app/workers/, ee/app/workers/, sidekiq_cluster/ Asynchronous jobs
Gitaly external gRPC service lib/gitaly_client.rb, gitaly Git repo storage and queries
GitLab Shell external Go binary gitlab-shell SSH entry point for git operations
KAS external Go service lib/gitlab/kas.rb, kas Talks to in-cluster agentk over gRPC
Pages external Go binary gitlab-pages Static site hosting

External services share a database with Rails through migrations defined here in db/.

The Rails monolith inside app/

The app/ and ee/app/ trees follow Rails conventions plus a few GitLab-specific layers:

graph TD
    subgraph "Inbound"
        C[controllers/]
        API[lib/api/ - REST]
        GQL[graphql/]
        CH[channels/]
    end
    subgraph "Authorization"
        Pol[policies/<br/>declarative_policy]
    end
    subgraph "Business logic"
        Svc[services/<br/>~130 namespaces]
        Fnd[finders/<br/>read-only queries]
    end
    subgraph "Data"
        Mod[models/<br/>ActiveRecord]
        Wkr[workers/<br/>Sidekiq jobs]
        Evt[events/<br/>Gitlab::EventStore]
    end
    subgraph "Output"
        Ser[serializers/]
        Pres[presenters/]
        Mlr[mailers/]
        Hlpr[helpers/ + views/]
    end

    C --> Pol
    API --> Pol
    GQL --> Pol
    Pol --> Svc
    Pol --> Fnd
    Svc --> Mod
    Svc --> Wkr
    Svc --> Evt
    Fnd --> Mod
    Mod --> Ser
    Svc --> Ser
    Mod --> Pres
    Svc --> Mlr
    Mod --> Hlpr

Conventions:

  • Controllers (app/controllers/) handle HTTP, do auth via Devise/Doorkeeper, and call services.
  • Services (app/services/) contain business logic. Most subclass BaseService or BaseContainerService and expose #execute returning a ServiceResponse (app/services/service_response.rb).
  • Finders (app/finders/) wrap read-only queries with permission filtering. ~46 finder namespaces.
  • Policies (app/policies/) use the declarative_policy gem to express ability checks like can?(user, :read_project, project).
  • Workers (app/workers/) are Sidekiq jobs. Queues are declared in config/sidekiq_queues.yml and routed by a Gitlab::SidekiqConfig::WorkerRouter.
  • GraphQL (app/graphql/) is built on the graphql-ruby gem with batch loaders, mutations, and subscriptions.
  • Models (app/models/) are Rails ActiveRecord with extensive concerns. Inherit from ApplicationRecord (app/models/application_record.rb), with Ci::ApplicationRecord and SecApplicationRecord for the decomposed databases.

For deeper detail see Patterns and conventions.

Bounded contexts and feature categories

The codebase has two intersecting taxonomies:

  • Feature categories (config/feature_categories.yml) — ~155 product/engineering categories like continuous_integration, code_review_workflow, geo_replication, duo_chat. Every controller, service, worker, and gem declares one.
  • Bounded contexts (config/bounded_contexts.yml) — ~75 Ruby namespaces that group feature categories (Ci::, MergeRequests::, Authn::, Search::, Geo::, Ai::, etc.). New domain code must live inside a registered bounded context.

The split between application layer (controllers, REST endpoints, views) and domain layer (services/models/lib) is enforced by RuboCop cops in rubocop/cop/gitlab/.

Multi-database decomposition

The application runs against up to four PostgreSQL databases:

Database Purpose Models Source
main Most application data (users, projects, MRs) ApplicationRecord db/migrate/, db/structure.sql
ci CI builds, pipelines, jobs Ci::ApplicationRecord shared structure
sec Security findings, vulnerability data SecApplicationRecord shared structure (decomposed-sec)
jh JiHu-only data JhApplicationRecord (downstream only)

Connection routing is handled by gems/gitlab-database-load_balancing and gems/gitlab-database-data_isolation. See Database for migration patterns and load balancing.

Frontend architecture

The frontend has three flavors:

  1. Server-rendered HAML views (app/views/, ee/app/views/) plus per-page Vue islands.
  2. Single-file Vue.js apps under app/assets/javascripts/<feature>/ mounted into HAML containers.
  3. Standalone frontend islands (frontend_islands/, ee/frontend_islands/) — small, independently-built bundles for isolated features, compiled with Vite.

The main bundle is built with Webpack (config/webpack.config.js); frontend islands are built with Vite (vite.config.js). GraphQL is consumed via Apollo client.

See Frontend for more.

Key cross-cutting infrastructure

  • EventStore (lib/gitlab/event_store.rb) — Pub/sub built on Sidekiq. Domain events are published synchronously in transactions and consumed asynchronously by subscribers.
  • Application context (lib/gitlab/application_context.rb) — Per-request metadata (user, project, root namespace, feature category) propagated through logs, traces, and Sidekiq jobs.
  • Feature flags (config/feature_flags/, 463 YAML files) — Flipper-based runtime gating with strict lifecycle rules. See Feature flags.
  • Rate limiters (lib/gitlab/application_rate_limiter.rb) — Centralized rate limiting using Redis token buckets.
  • Internal events (lib/gitlab/internal_events.rb) — Schemaful product analytics events that flow to Snowplow and ClickHouse.

Companion services pinned to specific versions

graph LR
    Rails[Rails monolith<br/>this repo]
    Gitaly[Gitaly]
    Shell[GitLab Shell]
    KAS[KAS]
    Pages[Pages]
    Workhorse[Workhorse<br/>workhorse/]
    Zoekt[Zoekt indexer]
    EsIdx[ES indexer]
    OpenBao[OpenBao]

    Rails --gRPC--> Gitaly
    Rails -->|HTTP| Workhorse
    Workhorse --gRPC--> Gitaly
    Shell -->|API call| Rails
    Shell --gRPC--> Gitaly
    KAS -->|API call| Rails
    Pages -->|fetch zip| Rails
    Rails --HTTP--> Zoekt
    Rails --HTTP--> EsIdx
    Rails --HTTP--> OpenBao

Each external service has its own repo and release cycle; this repo pins their versions in root-level *_VERSION files (GITALY_SERVER_VERSION, GITLAB_SHELL_VERSION, etc.).

Further reading

  • Database — multi-DB, load balancing, migration rules.
  • Sidekiq jobs — queue routing, idempotency, deduplication.
  • GraphQL API — schema generation, subscriptions, complexity limits.
  • Feature flags — lifecycle, types, rollout.
  • Geo — multi-region replication.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – GitLab wiki | Factory