What GitLab server requirements decide before you provision
Sizing a self-managed GitLab instance starts from three inputs: how many users you will have, how many API requests per second they will generate, and how much CI/CD load your pipelines will place on the platform. GitLab publishes reference architectures ranging from 1,000 users at 20 API requests per second to 50,000 users at 1,000 API requests per second, and those published shapes are the defensible starting point for a hardware and database baseline. Pick the closest reference architecture to your forecast, then adjust for your own repository sizes, runner fleet and growth.
Several components carry most of the requirements, and each one scales differently. The application nodes handle web and API traffic, Sidekiq processes background jobs, Gitaly serves Git repository data and is sensitive to local disk performance, PostgreSQL holds metadata and needs the most careful capacity planning, Redis supports caching and job queues, and object storage holds artifacts, LFS objects, uploads and other large files. Gitaly storage should be local, fast disk rather than NFS, a point covered in the storage section. Ask your team which component will hit its limit first, because that answer determines where the money and effort go.
Treat any figure you read here as a starting point, not a final spec. GitLab revises its requirements with each release, and the database and Redis versions that a given GitLab release supports are listed in its installation documentation for that exact version. Before you order hardware or sign a managed database contract, confirm the vCPU, memory, storage and version numbers against the docs for the release you plan to install, and record that check in your build decision log so an auditor or future operator can see which baseline you used.
Which reference architecture fits your user count
The smallest published reference architecture is sized for 1,000 users and about 20 API requests per second. At this scale, a single-node or small multi-node layout is usually discussed first, and the main sizing question is whether your daily load stays close to the published request rate. Teams with heavy CI activity, large monorepos or frequent automated API calls should not assume a user count alone decides the size.
- Published load point: The reference architecture for this tier is defined by 1,000 users and 20 API requests per second.
- Single-node starting point: Smaller organizations often begin with one virtual machine, which keeps backups and upgrades simple.
- CI and automation load: Pipeline volume, webhooks and bot traffic can exceed what the user count suggests.
- Storage growth: Repository size and job artifacts grow over time and should be planned separately from compute.
- Upgrade effort: A single node still requires planned maintenance windows and required upgrade stops.
Confirm the specification table for your chosen GitLab release and measure your current API request rate before copying any vCPU or memory figure.
Between the 1,000-user and 3,000-user points, the question shifts from raw capacity to resilience. Growing organizations in this range often move from a single node to a multi-node reference architecture that separates Gitaly, PostgreSQL, Redis and application components. The published guidance becomes more explicit as headcount approaches the high availability threshold.
- Component separation: Splitting roles across machines reduces contention between Git operations, database queries and background jobs.
- Scaling step: Move up a tier when measured API load or user count approaches the next published point.
- Change in maintenance: Multi-node layouts need coordinated upgrades and tested backups for each component.
- Growth planning: Decide early whether the next tier will be needed within your planning horizon.
- Cost of complexity: More nodes add monitoring, patching and networking work for your operations team.
Check the reference architecture page for your target release and compare your measured peak load with the published request rate for each tier.
The GitLab documentation generally recommends a high availability strategy from 3,000 users. That strategy uses Gitaly Cluster with Praefect for repository storage, PostgreSQL with Patroni for database failover, Redis Sentinel for cache and queue availability, and Consul for service discovery. Each component adds design work for network paths, failover testing and recovery procedures.
- Gitaly Cluster with Praefect: Repository data is replicated across Gitaly nodes, which requires local storage on each node.
- PostgreSQL with Patroni: Automated failover depends on correct cluster configuration and tested switchover.
- Redis Sentinel and Consul: These provide failover and service discovery for the components that depend on them.
- Testing burden: Failover, restore and upgrade procedures should be rehearsed before go-live.
- Stateful services outside Kubernetes: The reference architectures do not support running PostgreSQL or Redis inside Kubernetes.
Confirm the high availability specification table and the required components for your release before you request a quote.
The largest published reference architecture covers 50,000 users and 1,000 API requests per second. At this scale, the architecture is a large, distributed system with many nodes and dedicated roles for each component. Most organizations at this size need a detailed capacity plan, a documented disaster recovery approach and a clear owner for each stateful service.
- Published load point: The top tier is defined by 50,000 users and 1,000 API requests per second.
- Distributed roles: Application, Sidekiq, Gitaly, database and cache components typically run on separate hosts.
- Disaster recovery: Geo can provide a warm-standby secondary site in another region, which is available in the Premium and Ultimate tiers.
- Operational ownership: Assign owners for storage, database, runners and monitoring before the build starts.
- Specification review: Hardware and software requirements change by release, so the current tables must be checked for your version.
Ask your implementation partner or GitLab for a written sizing review that uses your measured load, not only the user count.
How Gitaly, PostgreSQL and Redis hosting options compare
This table compares the four hosting choices for GitLab's stateful components: bundled Linux package services, separate VMs, managed database and cache services, and object storage. Read each row against your own operating model, because the operator keeps backups, patching and failover in most options. The main takeaway is that PostgreSQL and Redis cannot run inside Kubernetes under the Cloud Native Hybrid architecture, so Kubernetes deployments need VM or managed services for those components.
| Component | Hosting option | When it fits | What the operator still owns |
|---|---|---|---|
| Gitaly storage | Bundled Linux package on the GitLab node | Single-node or small instances where one server holds Git data on local SSD | Disk capacity, filesystem choice, backups of repository data and host patching |
| Gitaly storage | Dedicated Gitaly VMs with local SSD | Larger instances that need repository storage separated from application load | Node sizing, Gitaly Cluster with Praefect at higher user counts, and failover testing |
| Gitaly storage | NFS mount | Discouraged by GitLab for Gitaly, so treat it as a migration source rather than a target | Plan the move to local SSD and object storage, as described in the NFS migration topic |
| PostgreSQL | Bundled Linux package database | Small instances where one node carries the database with the application | Backups, major version upgrades, tuning, patching and any replication or failover design |
| PostgreSQL | Self-managed PostgreSQL on separate VMs with Patroni | High availability at larger scale, as the reference architectures describe | Cluster operations, failover drills, connection handling and backup verification |
| PostgreSQL | Managed PostgreSQL service from a cloud provider | Teams that want the provider to run instance operations and their admin model fits GitLab's requirements | Provider role setup, supported version limits per GitLab release, backups and GitLab upgrade compatibility |
| PostgreSQL in Kubernetes | Stateful PostgreSQL inside Kubernetes | Not supported for GitLab under the Cloud Native Hybrid architecture | Use VMs or a managed service for PostgreSQL even when the stateless components run on Kubernetes |
| Redis | Bundled Linux package Redis | Small single-node instances | Persistence settings, memory headroom, patching and restart behavior |
| Redis | Redis Sentinel on separate VMs | High availability deployments that follow the reference architectures | Sentinel quorum, failover testing and version alignment with GitLab |
| Redis | Managed Redis service | Teams that want the provider to run the service, subject to confirming GitLab support for that service and version | Confirm supported configuration with GitLab, plus access controls, maintenance windows and monitoring |
| Redis in Kubernetes | Stateful Redis inside Kubernetes | Not supported for GitLab under the Cloud Native Hybrid architecture | Use VMs or a managed service for Redis in that architecture |
| Object storage | Cloud object storage or a compatible S3 service | Artifacts, LFS, uploads, packages and other object types that move off local disk | Bucket policies, lifecycle rules, encryption keys, backup scope and confirming provider support per data type |
Why burstable instances and NFS are discouraged for GitLab
Burstable instance types and NFS-backed Gitaly storage are discouraged for self-managed GitLab because both can look adequate in a quick test and then fail under sustained load. Burstable instances accumulate CPU credits while idle and spend them under load. Once the credits are gone, the instance is held to its baseline performance. A GitLab instance serving Git over SSH and HTTPS, running CI pipelines through Runners and processing Sidekiq background jobs rarely stays idle for long. The result is throttled Git operations, slow web requests and queued jobs that appear to come from GitLab itself when the cause is the instance type. Ask your cloud provider how credit accrual and baseline performance work for the exact instance family you plan to use, and check whether the sizing you chose holds through a full working day of pipeline activity.
Gitaly is the component that performs repository reads and writes, and it depends on fast, local file operations and reliable file locking. NFS adds network round trips to every operation and its locking semantics can differ from a local disk, which makes repository I/O slower and less predictable and can complicate concurrent access. For this reason the reference architectures call for local SSD storage for Gitaly, and object storage for data types such as job artifacts and LFS objects. Treat the storage type in the reference architecture documentation as the baseline for your sizing, and review the related guidance on moving off NFS before you build. Confirm current vendor guidance for your own storage platform, including how block volumes, file services and disk types behave under sustained I/O, rather than assuming a product is suitable because it is mounted as a POSIX file system.
How to size a GitLab deployment step by step
This sequence turns a user count and workload profile into a documented GitLab sizing decision, so the release, database versions, hosting model and storage design are settled before any infrastructure is ordered.
Define users, API load and CI demand
Start by writing down the number of named users, the expected concurrent activity, the rough API request rate and the CI/CD job volume you expect at peak. Your identity, security and platform teams should agree on these figures, since they drive every later choice. The step is done when you have a single signed-off sizing sheet that states the user count, the API load assumption and the pipeline volume, with the source of each estimate noted. Ask your GitLab partner or the reference architecture documentation to confirm which load band your numbers fall into.
Choose the reference architecture
Match your sizing sheet to the closest published GitLab reference architecture, which the documentation lists from 1,000 users at 20 API requests per second up to 50,000 users at 1,000 API requests per second. Note that GitLab generally recommends a high availability strategy at 3,000 or more users, which changes the component count significantly. The output is a named reference architecture and a list of the components it requires, including Gitaly, PostgreSQL, Redis, Sidekiq and the application nodes. Check the architecture page again before you commit, because the documented specifications change between releases.
Confirm the GitLab release and database versions
Select the GitLab release you will deploy, then check the maintenance policy and the upgrade paths documentation for the PostgreSQL and Redis versions that release supports. Also confirm the required upgrade stops if you will upgrade later from an older version. The output is a written release decision with its supported PostgreSQL and Redis versions recorded in the sizing document. If the release you want is not on a currently maintained line, stop here and choose again, because bug fixes are backported only to the current stable release and security fixes only to the previous two monthly releases.
Select the hosting model for each component
For each component, decide whether it runs on VMs, on a managed service, or in another supported arrangement. The reference architectures document states that PostgreSQL and Redis are not supported inside Kubernetes, and the Cloud Native Hybrid architecture keeps stateful services on VMs or managed services. Record the decision per component, including whether managed PostgreSQL and managed Redis meet the version and extension requirements for your chosen release. Confirm each provider's support matrix with the vendor before you rely on it.
Size Gitaly local SSD storage
Estimate Gitaly storage from your repository inventory, including the total size of existing repositories, expected growth over the planning period, and headroom for repository maintenance and backups staged on the same host. Use local SSD block storage for Gitaly, and avoid NFS, since the documentation discourages it for this data. Also review burstable instance types, which the documentation discourages for production components. The output is a Gitaly volume plan with capacity, IOPS expectations and a growth review date. Verify the plan with a test restore of a representative repository set.
Plan object storage and backup capacity
List the data types that belong in object storage, such as artifacts, LFS objects, uploads, package and container registry data, and CI job logs where the configuration supports it. Size each bucket or container from current usage and retention rules, then size backup targets separately so backups do not compete with live data. The output is a storage table that maps each data type to a bucket, its retention setting and its backup location. Confirm which object storage providers GitLab tests and which it documents from the community before you commit to a provider.
Validate with a test instance
Build a non-production instance at the chosen release with the planned component layout, then load it with a representative sample of repositories and a synthetic CI workload that approximates your peak. Measure CPU, memory, disk latency and database connection use during the run, and compare the results with the reference architecture targets. The step closes when the test results support the sizing sheet, or when you have revised the sheet and rerun the test. Keep the test report with the sizing record, since it becomes the baseline for later capacity reviews and upgrade planning.
Security considerations for the server baseline
Sizing a GitLab server is also a security decision. Each component you size, from the database and Redis to Gitaly and runners, adds an attack surface and a data store that needs protection. The cards below cover the controls that should be designed in alongside the CPU, memory and storage numbers.
Restrict database and Redis access
PostgreSQL and Redis hold credentials, session data and project metadata, so they should accept connections only from the application and Sidekiq tier. When you size these services separately, define the network paths, firewall rules and authentication for each one before the build starts. Confirm that no database port is reachable from user networks or runner subnets, and review the setting each time you add a node.
Encrypt Gitaly and object storage
Gitaly volumes hold every repository, and object storage holds job artifacts, LFS objects and package data. Plan encryption at rest for both, either through the disk and bucket encryption your cloud or data center provides or through a key management service you operate. Ask your storage team how keys are rotated and who can read the volumes outside GitLab.
Separate backup storage
Backups contain the same repositories and database contents as production, so storing them on the same volumes or under the same credentials removes the protection a restore depends on. Keep backup targets in a separate account or failure domain with write-only access for the GitLab service account. Confirm the procedure for restoring the secrets file alongside the data, as described in the backup documentation.
Apply hardening in stages
The operating system and GitLab hardening guidance covers application settings, CI/CD, gitlab.rb and the host itself. GitLab describes this guidance as a work in progress to be rolled out gradually. Apply changes in a staging instance first, record each setting in version control, and test sign-in, pipelines and backups after each stage so that a security change does not become an outage.
Isolate runner hosts from core servers
Runners execute code from pipelines, and that code can be untrusted. Run runner hosts on separate networks from the Gitaly, database and Redis tier, and give them only the credentials their jobs need. Avoid placing runners on the GitLab application hosts, and confirm the executor type and isolation model with your runner design before you size the fleet.
Confirm access and secrets scope
Administrative access to the Linux package host, the gitlab-secrets.json file and the database role determines who can read everything above. Limit operating system accounts to named administrators, keep secrets out of shared configuration repositories, and confirm which team can rotate the database password. Review these access lists at each sizing change, since new nodes and roles add paths to the data.
Questions teams ask before sizing GitLab
How much hardware and effort does sizing a self-managed GitLab instance take?
Sizing starts from measured usage, not a fixed server profile. The reference architectures published by GitLab range from 1,000 users at 20 API requests per second to 50,000 users at 1,000 API requests per second, so your user count, API load and CI activity decide which tier of CPU, memory and storage you need. Effort depends on how much usage data you already have. Teams with clean metrics from their current Git host need less discovery time. Ask for the sizing inputs to be listed in the written scope before work starts, including which components (Gitaly, PostgreSQL, Redis, Sidekiq) will be measured and which are assumed.
What drives the cost of running GitLab up or down?
The main drivers are user count, CI load, and the availability design you require. GitLab recommends a high availability strategy for 3,000 or more users, which adds Gitaly Cluster with Praefect, PostgreSQL with Patroni, Redis Sentinel and Consul, and each extra node carries compute, storage and operations time. A disaster recovery requirement adds a second site. GitLab Geo, available in the Premium and Ultimate tiers, provides a warm-standby secondary site that is continuously synchronized. Subscription cost depends on the tier. The GitLab pricing page lists Free at 0 US dollars, Premium at 29 US dollars per user per month billed annually, and Ultimate as custom priced. Infrastructure is one-time setup plus recurring cloud or hardware cost.
Can a small team size and run GitLab without outside help?
A small team can do it if it has someone comfortable with Linux administration, PostgreSQL, backups and upgrades, and time to test under realistic load. Single-node installs from the Linux package are documented and bundle PostgreSQL, Redis and Sidekiq, so a small instance is a manageable project. The harder part is the ongoing work: required upgrade stops, monthly minor releases, backup restore testing and monitoring. Be honest with yourself about who owns those tasks after go-live. A partner can cover the sizing and build, a retainer can cover upgrades and support, or your team can keep all of it in-house.
What does the work need from our team before validation starts?
You need to provide usage data, a growth forecast and the constraints that shape the architecture. Usage data includes current repository size, number of active users, peak API request rates, and CI job volume and duration. The growth forecast should cover the next planned hiring and project waves. Network constraints include whether the instance must run offline or in an air-gapped network, which GitLab documents separately. Identity constraints include the authentication method, such as SAML, LDAP or SCIM, and whether Kerberos or smart card access is required. Confirm also which cloud accounts, data centers or hardware you can use, because that sets the database and object storage options.
How long does sizing validation usually take?
The duration depends on your environment, so confirm it against your own inputs rather than a generic figure. Validation time grows with the number of systems in scope, the quality of your usage data, and whether you need load testing on the target hardware. Approval steps inside your organization, such as security review of the chosen database or object storage service, often take longer than the technical work. Ask for the validation plan to list each step, the people needed from your side, and the dates on which your input is expected.
What should we ask for in a fixed-scope quote for GitLab sizing?
Ask for a written scope that names the deliverables, the environments covered and the acceptance criteria. Good quotes state which GitLab release and edition are assumed, which reference architecture or sizing method is used, and which components are measured under load. They should list what is one-time, such as design, build and validation, and what recurs, such as upgrades and support. Ask how changes to user count or CI load after sign-off are handled, what the client must provide and by when, and which tests prove the sizing. Fixed-scope engagements are agreed in writing before work starts, so make sure every assumption appears in that document.
Which GitLab release should we size against, and how often does it change?
Size against a release that is currently maintained and plan for upgrades from day one. GitLab ships a major release yearly, a minor release on the third Thursday of each month, and patch releases twice a month, and it currently maintains 19.5, 19.4 and 19.3. GitLab requires upgrades to pass through required upgrade stops, which since GitLab 17.5 fall at versions x.2, x.5, x.8 and x.11. Database and Redis version support also changes by release, so confirm the exact PostgreSQL and Redis versions for your target release with GitLab's documentation before you choose the hardware.
How upgrade stops change the database and runtime baseline
A sizing record for self-managed GitLab is only accurate for the release it was written against. Between required upgrade stops, the PostgreSQL and Redis versions that GitLab expects can change, so the baseline should be tied to a named target release rather than to whatever version is running today. Since GitLab 17.5, required upgrade stops fall at x.2, x.5, x.8 and x.11, for example 18.2, 18.5, 18.8, 18.11 and 19.2, 19.5, 19.8 and 19.11. Check the upgrade path for both your current release and your target release before you commit to a database engine or version, and record the result next to the CPU, memory and storage figures.
GitLab ships a minor release on the third Thursday of each month, patch releases twice a month and a major release yearly. The maintenance policy backports bug fixes only to the current stable release, while security fixes also go to the previous two monthly releases. That means an instance that falls behind a stop can be left without fixes for ordinary defects, and a database or Redis version that was supported at install time may no longer be the one a current release needs. Plan the target release as a supported version from the start, and set a review point for each upcoming stop so the database and runtime baseline is revisited before the upgrade window, not during it.
Ask your implementation partner or your own platform team to confirm three things in writing: the PostgreSQL and Redis versions required by the target release, whether a managed database service offers those versions in your region, and whether the upgrade path to that release passes through a stop that requires a database major version change. Where a stop changes the database, the work includes a backup taken before the change, a tested restore and time for the database upgrade itself, so these items belong in the upgrade plan and the sizing record together.
What DeployOpen scopes before any hardware is ordered
Sizing a self-managed GitLab instance starts with written decisions, not servers. The four deliverables below connect the user and CI load forecast to the layout, database and storage choices, and the checks that prove the build matches the plan. Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts. DeployOpen does not publish prices; a quote follows from the written scope.
Written requirements worksheet
A worksheet records named users, concurrent active users, API request rate, repository count and largest repository size, CI job volume and peak concurrency, and the availability target. It also records which GitLab release line will be installed and the upgrade stops it must cross. Without these inputs, any CPU or memory figure is a guess. Ask the vendor or your team to confirm the forecast numbers before anything is sized.
Sized reference layout
The layout maps the worksheet to a published reference architecture or a documented variant, then names the node count, vCPU and memory per role, and whether Gitaly, PostgreSQL, Redis and Sidekiq share hosts. It states the cloud or data center target and whether stateful services run on VMs or managed services. Confirm that the chosen layout matches the GitLab version you will deploy, since requirements change between releases.
Database and storage plan
This plan sets the PostgreSQL and Redis versions for the target release, the Gitaly storage type on local disks rather than NFS, and where object storage holds artifacts, LFS, uploads and packages. It covers backup targets and restore timing, and whether the database is self-managed or a managed service with the extensions GitLab needs. Ask for the version matrix in writing and confirm each entry against the release notes before purchase.
Validation checklist
The checklist is the acceptance test for the sizing: load test results against the forecast API rate, disk latency and free space on Gitaly volumes, database connection limits, Redis memory headroom, and a restore test from a recent backup. It also confirms that runners are version-aligned with GitLab and that upgrade stops are scheduled. Each item needs a named owner and a pass condition agreed before the build starts.
How DeployOpen scopes and delivers GitLab sizing
DeployOpen plans, implements, hardens, documents and supports self-hosted GitLab inside your own cloud accounts, data centers or air-gapped networks. For server requirements, we start from your user count, CI load and storage profile, then turn them into a written sizing baseline that your team can review and approve before any hardware is ordered.
How we scope
- Engagements are fixed-scope, with sizing inputs, deliverables and timelines agreed in writing before work starts.
- We collect user counts, peak CI job volume, repository size and growth expectations to define the sizing baseline.
- Scope names the target GitLab release, the PostgreSQL and Redis versions that release supports, and the installation method.
How we build
- We size vCPU, memory and Gitaly storage against the published reference architecture closest to your workload.
- We check PostgreSQL and Redis versions against the GitLab release you plan to run, and flag any version limits before build.
- We test burstable instance choices and NFS storage assumptions, and document why each recommendation was made.
How we hand over
- You receive a written sizing record covering hardware, storage layout, database and Redis versions, and the upgrade stops in your plan.
- Documentation explains how to monitor CPU, memory, disk and database load so you can recognize when capacity needs to grow.
- Your team is walked through the sizing decisions, the trade-offs behind them and the questions to raise with GitLab or your cloud provider.
How we support
- Ongoing support, upgrades and continuous testing are available as retainers after handover.
- When GitLab releases change version requirements, we review the sizing baseline against the new release before you upgrade.
- Retainer scope, response expectations and review cadence are confirmed in writing with the quote.

