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 --> CHThe 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 --> HlprConventions:
- Controllers (
app/controllers/) handle HTTP, do auth via Devise/Doorkeeper, and call services. - Services (
app/services/) contain business logic. Most subclassBaseServiceorBaseContainerServiceand expose#executereturning aServiceResponse(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 likecan?(user, :read_project, project). - Workers (
app/workers/) are Sidekiq jobs. Queues are declared inconfig/sidekiq_queues.ymland routed by aGitlab::SidekiqConfig::WorkerRouter. - GraphQL (
app/graphql/) is built on thegraphql-rubygem with batch loaders, mutations, and subscriptions. - Models (
app/models/) are Rails ActiveRecord with extensive concerns. Inherit fromApplicationRecord(app/models/application_record.rb), withCi::ApplicationRecordandSecApplicationRecordfor 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 likecontinuous_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:
- Server-rendered HAML views (
app/views/,ee/app/views/) plus per-page Vue islands. - Single-file Vue.js apps under
app/assets/javascripts/<feature>/mounted into HAML containers. - 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--> OpenBaoEach 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.