Using the GitLab Environment Toolkit to deploy a reference architecture
The GitLab Environment Toolkit is a set of Terraform and Ansible code that builds a self-managed GitLab reference architecture in a cloud account you own. It fits a platform team that must stand up GitLab in its own AWS, GCP or Azure account and wants a repeatable starting point to test against before committing to a design. Terraform provisions the cloud layer, such as networks, virtual machines, load balancers and storage, and Ansible installs and configures GitLab and its supporting services on those hosts. The reference architectures it targets range from 1,000 users (20 API requests per second) to 50,000 users (1,000 API requests per second), so the first decision is which size matches your measured request load and CI demand.
Treat the output as a starting point that still needs production work. GitLab generally recommends a high availability strategy from 3,000 users, using Gitaly Cluster with Praefect, PostgreSQL with Patroni, Redis Sentinel and Consul, so confirm which of these the toolkit release you choose builds and which it leaves to you. If your plan involves Kubernetes, check the reference architectures documentation first: running PostgreSQL or Redis inside Kubernetes is not supported. Your team still owns DNS, TLS certificates, the backup schedule and restore tests, monitoring, the runner fleet, and the required upgrade stops, which fall at the x.2, x.5, x.8 and x.11 releases (for example, 19.2, 19.5, 19.8 and 19.11). GitLab reference architectures lists the sizing targets to check against.
GitLab's source is open core. Content under the ee/ directory is licensed under the GitLab Enterprise Edition license, and content outside it is available under the MIT Expat license, according to the LICENSE file in the gitlab-org/gitlab repository. Confirm the license of the toolkit repository itself before you fork or embed it. The tier you run decides which features the deployed instance has: the pricing page lists GitLab Free at 0 US dollars, Premium at 29 US dollars per user per month billed annually, and the higher tier as custom priced. Geo, the warm-standby disaster recovery option, requires Premium or the higher tier. Cloud compute, storage and network charges are paid to your provider and recur each month, while the implementation work is usually a one-time cost. Ask for the toolkit work, the cloud footprint and the GitLab subscription to be quoted as separate lines.
What the toolkit builds in your cloud account
The toolkit splits the work into layers: infrastructure, GitLab configuration, stateful services, application roles and traffic entry. Each layer maps to a reference architecture choice, and several decisions stay with your team even after the build completes.
Network and compute with Terraform
Terraform modules define the network, subnets, security groups and virtual machines for each role in the chosen reference architecture. Check the node counts and instance sizes against that architecture's documented targets, not against your headcount alone. Confirm that your cloud account has the quotas, regions and IAM permissions the modules need before the first apply, and agree who owns the state file and its encryption.
GitLab configuration with Ansible
Ansible roles install the Linux package on each node and write the role-specific settings into gitlab.rb. The playbooks also decide which node runs which service, so a mismatch between inventory and architecture is a common early fault. Your team must still decide how secrets such as database passwords and the GitLab secrets file reach the playbooks, and how configuration changes are reviewed and versioned.
Gitaly, PostgreSQL and Redis tier
Stateful services hold the repositories, database and cache. At higher user counts the reference architectures use Gitaly Cluster with Praefect, PostgreSQL with Patroni, and Redis Sentinel with Consul. Stateful services run on virtual machines or managed services, not inside Kubernetes, so confirm early whether your platform team will accept that model. Replication settings and failover tests determine recovery time, so plan those tests before go-live.
Rails and Sidekiq application nodes
Application nodes run the web-facing Rails processes and the Sidekiq background workers. The reference architectures separate these roles, which lets you scale background job capacity independently of web capacity. Confirm how many nodes each role gets for your expected API load, and check how CI job volume will affect Sidekiq queues, because the toolkit's defaults are a starting point rather than a measured fit for your workload.
Load balancing and traffic entry
The load balancer distributes HTTP, HTTPS and Git over SSH traffic across the application nodes. Your team still decides the DNS names, TLS certificate source and renewal process, health check paths, and whether internal users reach GitLab through a different address than external users. Test each entry point, including large Git clones, because timeouts often appear there first.
Decisions the toolkit leaves open
Before you assume a component is built, confirm it against the toolkit documentation for your version. Backup storage, a Geo secondary site, the runner fleet, monitoring and log shipping often need separate design. Treat each as a named decision with an owner, because a deployment that starts successfully can still lack the recovery and operations pieces needed for production.
How the toolkit differs across AWS, GCP and Azure
On AWS, the toolkit's Terraform code provisions the network, compute, load balancing and storage for the reference architecture, so the first confirmation is the IAM identity that runs Terraform. It needs permission to create networking, instances, load balancers, storage buckets and any database or key resources the chosen layout uses. Ask your cloud team whether a dedicated deployment account or role with scoped permissions is available, and whether service quotas for instances and addresses are high enough for the chosen size.
- IAM permissions: Confirm the role can create every resource type the toolkit's current AWS code uses, and that policy boundaries or service control policies do not block them.
- CIDR planning: Reserve VPC and subnet ranges that do not overlap with peered networks, VPN ranges or other clusters, because changing them later is disruptive.
- Managed or self-run services: Decide whether PostgreSQL, Redis and object storage run as managed AWS services or on VMs you operate, and check the toolkit's current support for each choice.
- Terraform state: Choose a remote backend with locking and encryption for the state file, and confirm who may read it, since state can hold sensitive values.
- Provider support: Check the toolkit's current AWS support and supported versions in its documentation before you plan the build.
Confirm each item against your own AWS account and the toolkit release you intend to use.
On GCP, the toolkit's Terraform code works within a project or set of projects, so the first decision is whether GitLab gets its own project. Service account roles, enabled APIs and organization policies determine whether Terraform can create the network and compute resources. Confirm with your platform team whether organization policies restrict external IPs, service account keys or specific regions, because these settings can block a build midway.
- Service account roles: Grant the Terraform identity only the roles the toolkit's current GCP code needs, and confirm which APIs must be enabled in the project first.
- Network CIDR planning: Plan VPC subnet ranges and secondary ranges against existing shared VPCs, and avoid overlap with on-premises networks you will reach by VPN or interconnect.
- Managed or self-run services: Decide which stateful roles use managed Google Cloud services and which run on VMs, and check the toolkit's current support for that split.
- State storage: Use a Cloud Storage bucket as the Terraform backend with versioning and restricted access, and confirm who may read the state.
- Organization policies: Check constraints on regions, public IPs and key management before the first apply.
Verify each item against your project structure and the toolkit's current GCP documentation.
On Azure, the toolkit's Terraform code deploys into a subscription and resource group structure, so the first checks cover subscription access and the identity used by Terraform. Azure role assignments and resource provider registration can block resource creation even when the template is correct. Ask whether your subscription sits under management groups or policies that restrict regions, network ranges or public endpoints.
- Identity and roles: Confirm the service principal or managed identity has the role assignments needed at subscription or resource group scope, and that resource providers are registered.
- Network CIDR planning: Reserve virtual network and subnet ranges that avoid overlap with hub networks, VPN gateways and other workloads.
- Managed or self-run services: Decide which database, cache and storage roles use Azure managed services and which run on VMs, and check which combinations the toolkit currently supports.
- State storage: Use an Azure Storage account container as the Terraform backend, with access restricted and blob versioning or soft delete enabled as your policy requires.
- Policy and compliance: Review Azure Policy assignments that could deny resources the toolkit creates, such as public IP or encryption settings.
Confirm these points against your subscription and the toolkit's current Azure documentation before running Terraform.
Some decisions stay the same whichever provider you choose, and they often decide whether the build succeeds on schedule. The provider tabs cover platform-specific prerequisites, but the network, state and stateful service choices shape the whole architecture. Treat these as a common checklist that every provider must pass before any apply runs in a shared environment.
- Stateful service ownership: Record who patches, backs up and restores PostgreSQL, Redis and Gitaly storage, because that owner is different for managed services and self-run VMs.
- Addressing across environments: Use one CIDR plan that covers production, staging and any disaster recovery region, so later sites do not need renumbering.
- Secrets and state handling: Keep Terraform state and generated credentials out of source control, and limit access to the state backend.
- Access to the deployment host: Confirm how operators reach private subnets, such as bastion hosts, VPN or a private runner, before relying on them.
- Toolkit version pinning: Pin the toolkit and Terraform versions you test, and record them with the environment, since provider support can change between releases.
Review this checklist with your cloud, network and security teams before any provider-specific work begins.
Multi-cloud teams often use one toolkit codebase for several providers, but each environment still needs its own variables, state and approvals. The risk is that a configuration tested on one provider is assumed to behave the same way on another. Keep provider differences visible in the repository so reviewers can see what changed for each target.
- Separate state per environment: Use distinct state files for each provider and environment so one plan cannot touch another.
- Reviewed variable files: Store provider-specific variable files under review, with values for regions, CIDRs and instance sizes.
- Plan review before apply: Require a reviewed plan output from each provider before a change reaches shared infrastructure.
- Drift checks: Schedule plan runs against deployed environments to detect changes made outside Terraform.
- Documented exceptions: Record any provider where a reference component was replaced or handled manually, with the owner of that choice.
Before you start, confirm the change process your organization requires for infrastructure, since it may need sign-off that the toolkit does not provide.
Which deployment option fits your reference architecture
This table compares the main layout choices for a GitLab reference architecture built with the toolkit: VM-based high availability, Cloud Native Hybrid, and where PostgreSQL and Redis run. Read each row against your user count, API request rate and the team that will operate the platform, then confirm the choice with the reference architecture documentation before you write the Terraform and Ansible inputs.
| Decision | Best fit when | Main trade-off |
|---|---|---|
| All components on VMs (standard reference architecture) | You want the layout GitLab documents most fully and your team already runs Linux VMs in your cloud account or data center | More nodes to patch and back up, and the Rails, Sidekiq, Gitaly and database roles all need separate capacity planning |
| Cloud Native Hybrid (stateless on Kubernetes) | You already operate a Kubernetes cluster and want Webservice and Sidekiq to scale as pods while stateful services stay outside the cluster | Two platforms to run, and PostgreSQL, Redis, Gitaly and object storage still need VMs or managed services |
| PostgreSQL inside Kubernetes | Not an option for a supported GitLab deployment, according to the reference architecture documentation | Stateful components in Kubernetes are not supported, so this layout is excluded from the design |
| Redis inside Kubernetes | Not an option for a supported GitLab deployment, according to the reference architecture documentation | Stateful components in Kubernetes are not supported, so Redis must run on VMs or a supported managed service |
| Managed PostgreSQL service | Your organization already runs a managed database service that GitLab supports and you accept the service's maintenance windows | Confirm version, extension and HA requirements with the GitLab documentation before you commit to it |
| Gitaly Cluster (Praefect) for repository HA | Repository-level high availability matters more to you than simpler storage operations | Adds replicas and failover components to operate, and backup behavior differs from sharded Gitaly |
| Sharded Gitaly | You prefer a simpler storage layer and can accept a different failover model for repositories | Confirm the limitations and backup approach with the Gitaly documentation before you choose it |
| Geo secondary site for disaster recovery | You need a warm-standby site in another region that stays continuously synchronized | Requires a Premium or Ultimate subscription and a second environment to build and maintain |
Deployment sequence with checks at each stage
The sequence moves from a written sizing decision to a tested, reachable GitLab instance with a proven restore path. Each step closes with a check, so a failure is caught before the next layer of infrastructure is built on top of it.
Choose the reference architecture
The platform owner and the engineering lead agree on the target reference architecture, starting from user count and API requests per second rather than headcount alone. GitLab's reference architectures run from 1,000 users at 20 API requests per second up to 50,000 users at 1,000 requests per second, and the documentation generally recommends a high availability design from 3,000 users. Record the choice, the expected CI load and any monorepo considerations in a sizing note. The step is done when the sponsor has signed that note and the architecture maps to a documented layout in the toolkit.
Prepare accounts and remote state storage
The cloud team creates the accounts, networks, identity roles and a remote backend for Terraform state, then confirms that only the deployment pipeline and named administrators can read or write that state. Decide now whether state and plan files will be encrypted with a customer-managed key, since OpenTofu supports encryption at rest for remote backends if you choose that tool. Pin the Terraform or OpenTofu version and the toolkit version in your repository. The check is a successful test write and read against the backend from the deployment runner, plus a recorded version pin.
Provision infrastructure with Terraform
The infrastructure engineer runs the toolkit's Terraform configuration for your chosen cloud, following the exact invocation in the toolkit documentation for the pinned version. Review the plan line by line, paying attention to instance counts, disk sizes, load balancers, object storage buckets and database tiers against the sizing note. Apply only after a second engineer has approved the plan. The check is that the apply completes without errors and that the resources in the cloud console match the plan and the sizing record.
Configure GitLab with Ansible
The platform engineer runs the Ansible playbooks from the toolkit against the inventory generated by Terraform, again using the documented commands for the pinned version. The playbooks install the Linux package components and assign node roles according to the chosen architecture. Store the generated secrets file and configuration in your secrets manager, not in the repository. The check is a clean playbook run followed by a successful administrator sign-in to the web interface on the new instance.
Confirm reachability and component health
The operations team tests each access path the business depends on: the web interface, Git over HTTPS and SSH, the load balancer address, and a runner registration against the instance. They also review the health and status output for each node and component against the monitoring guidance in the GitLab documentation. Include the database and Redis endpoints in this review, because a healthy web tier cannot hide a failed backend. The check is a short written test report listing each path and component as passing, with any exceptions assigned to an owner.
Run backup and restore tests
The operations team takes a backup using the GitLab backup procedure, then restores it into a separate environment built from the same toolkit version. The test covers repositories, database content, uploads and the secrets file, which the backup task does not replace on its own. Follow the GitLab backup and restore documentation for the steps and the items that sit outside the backup. The check is a restored instance where a sample of projects, merge requests and pipelines matches the source, with the elapsed restore time recorded.
Record the manual production gaps
The engineering lead lists every task the toolkit does not complete for your environment, such as TLS certificates, DNS, monitoring integration, alert routing, network policy, runner fleets and any authentication configuration. Each item gets an owner, a target date set by your own change process, and a link to the runbook that covers it. Confirm these items with the toolkit documentation for the pinned version, since its coverage changes between releases. The check is an approved go-live checklist with every gap closed or formally accepted by the sponsor.
Production steps the toolkit does not cover for you
The toolkit gives you a reference architecture, but it does not run your production service. Treat the items below as your own work packages, and confirm in the toolkit's current documentation which of them it touches at all before you assume anything. The first group is access and trust: DNS records and TLS certificates for the external URL, the registry and any Pages endpoints, plus renewal automation on the load balancers. Next is identity integration. Connect SAML, LDAP or OAuth providers, decide how group membership maps to GitLab roles, and test SCIM provisioning and deprovisioning with real accounts before go-live.
The second group is recovery, which is where most production gaps appear. Write a backup schedule that covers the database, Gitaly repositories and object storage, and back up the /etc/gitlab/gitlab-secrets.json file separately so encrypted data stays readable after a restore. Then run tested restores into a scratch environment and time them. Plan Gitaly and PostgreSQL recovery separately, because a repository-level failure and a database failure have different procedures. If you need a warm standby in another region, GitLab's Geo documentation describes the setup as a separate project.
The third group is operations. Build monitoring and alerting on the Prometheus metrics and health checks for every node role, and route alerts to a team that is staffed to respond. Stand up a GitLab Runner fleet with its own sizing, autoscaling, versioning and network access, because the toolkit does not decide which executors your pipelines need. Schedule upgrade stop planning against the required upgrade stops and the monthly and patch release cadence in the GitLab maintenance policy, and rehearse each upgrade in a non-production copy. Finally, apply the GitLab hardening recommendations in stages, starting with application settings and gitlab.rb, and record which controls you accepted, changed or deferred.
Security and operational risks to plan for
The toolkit automates a lot, but it does not remove the security and operational risks of a production GitLab estate. The six risks below share one root cause: infrastructure, secrets and configuration are spread across Terraform, Ansible and manual changes, and each layer needs its own controls.
Sensitive data in Terraform state
Terraform state records resource attributes, which can include credentials, endpoints and generated values. Decide where state lives, who can read it and how it is backed up before the first apply. OpenTofu, a drop-in Terraform replacement, encrypts state and plan files at rest for local and remote backends, so evaluate whether its state encryption fits your key management. Confirm that any migration keeps your existing workflows and remote state sharing working.
Over-broad cloud IAM roles
The toolkit needs permissions to create networks, compute, databases, storage and load balancers. Teams often grant administrator-level roles to make the first apply succeed and never narrow them. Ask for a role per stage (provisioning, configuration and backup), scope them to the project or account that hosts GitLab, and review them after the first build.
Secrets handled by Ansible
Ansible roles write the GitLab initial root password, database credentials, Redis passwords and the gitlab-secrets.json material into inventories and variable files. Keep these values in an encrypted store or external secrets manager, restrict who can run playbooks, and confirm that the secrets backup procedure covers what the playbooks generate.
Default exposure of the instance
A freshly built GitLab estate can expose the web, SSH and registry endpoints more widely than intended, especially when load balancers and security groups are generated with default ranges. Review sign-up settings, visibility defaults and network rules against your access model, then apply the hardening guidance in stages, since GitLab describes that guidance as a work in progress.
Drift between Terraform and Ansible
Terraform builds the infrastructure and Ansible configures what runs on it. When one tool changes a value the other assumes, such as instance sizes, IP addresses or node counts, the next run can fail or silently reconfigure a node. Run both tools from the same inputs, record which version of each produced the current environment, and check for drift before every change window.
Undocumented manual changes
Production fixes applied by hand, such as a tuned gitlab.rb setting or a console change, disappear on the next toolkit run or are lost during an upgrade. Record every manual change in version control with a reason and owner, and reconcile it back into code. Include the list of manual steps in your runbook so an upgrade or recovery does not depend on one engineer's memory.
Questions teams ask before deploying with the toolkit
Is the GitLab Environment Toolkit enough to run GitLab in production?
Not on its own, in most cases. The toolkit provisions and configures infrastructure that follows GitLab's reference architectures, which gives you a sound starting point. Production still needs decisions it does not make for you: backup and restore testing, monitoring and alert routing, identity integration, runner fleet design, DNS and TLS certificates, and an upgrade procedure that respects required upgrade stops. Read the toolkit's documented limitations for your chosen cloud and confirm which components it manages and which you run yourself. Ask for a written list of manual steps before go-live.
What costs come with deploying GitLab this way?
Costs fall into three buckets:
- Cloud resources, paid to your cloud provider under your own account. These recur monthly and rise or fall with instance sizes, storage and the reference architecture you choose.
- Internal team time for ownership of the environment, including upgrades, on-call, access reviews and restore tests. This recurs for as long as you run GitLab.
- A partner's scoped work, billed against a written scope that covers provisioning, hardening, testing and handover. The build is normally one-time, while support and upgrades can run as a recurring retainer.
GitLab Premium is listed at 29 US dollars per user per month billed annually, and the Free tier costs nothing, so licensing may be a separate line. Ask any quote to itemize these buckets and mark which items recur.
How long does a toolkit deployment take?
Duration depends on scope more than on the toolkit itself. The main drivers are the target reference architecture, the number of environments such as staging and production, how many integrations you build at deployment time (SSO, runners and object storage, for example), how much hardening and load testing you require, and how quickly your cloud accounts, network approvals and DNS changes arrive. No duration here is a promise. Ask for a timeline in the written scope with milestones tied to each deliverable, and ask which steps wait on your internal approvals so you can see where the schedule is most likely to slip.
What does our team need to provide before the build starts?
Plan to supply these items before the build starts:
- Cloud accounts or subscriptions on AWS, GCP or Azure, with permission to create networks, compute, managed storage and load balancers in the target region.
- Network plans, including address ranges, VPN or peering to corporate networks, egress rules and the DNS zones to use.
- An identity provider decision, with application details for SAML or OIDC and the group mappings your access model needs.
- DNS names and TLS certificates for the GitLab URL and any other GitLab-hosted domains.
- Named owners for backups, on-call duty and access approvals.
Ask the provider to attach this supply list to the written scope so that missing items are visible before the schedule is set.
Can our own engineers deploy GitLab with the toolkit without a partner?
Yes, if your team has cloud infrastructure experience, already runs Terraform or Ansible in its own pipelines, and can own the result after go-live. The toolkit is built for teams that will operate what they deploy. The gaps usually appear after the first deployment, in day-two work: restore tests, upgrades through required upgrade stops, failure drills for Gitaly and PostgreSQL, and documenting every deviation from the reference architecture. Assess your team against those tasks honestly. A partner's scoped work can cover the build, the runbooks and the handover, while your staff keep ongoing ownership.
Does OpenTofu work with the toolkit if we use it instead of Terraform?
OpenTofu describes itself as a drop-in replacement for Terraform that preserves existing workflows and configurations, and it is licensed under the Mozilla Public License 2.0. Whether the toolkit's modules and your pipeline are tested with the OpenTofu version you run is a separate question, so confirm it against the toolkit documentation and in your own test environment. OpenTofu also states that compatibility with future Terraform releases is not guaranteed. For a move from Terraform, the migration guide describes four steps: back up state and code, install OpenTofu, initialize and verify, then test with a small change. Configurations that use terraform_remote_state need extra care.
Does a partner's fixed-scope engagement cover the whole deployment?
It covers what the written scope says it covers, which is why the scope matters most. Most engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts. For a toolkit deployment, the scope would normally name the target cloud, reference architecture, environments, integrations, hardening, tests, the handover package and the items your team provides. Ongoing support, upgrades and continuous testing are available as retainers, which cover the day-two work that a build does not. Ask for an itemized quote tied to that scope and ask what changes the price if requirements shift during the build.
Limits to confirm in your environment before go-live
The Environment Toolkit gets a GitLab reference architecture built quickly, but several limits sit outside the code and remain your responsibility. Confirm each item below against your own provider, GitLab version, Terraform or OpenTofu version, network rules and recovery requirements before you accept the environment for production use.
Provider and architecture support
Confirm that the toolkit's current release supports your chosen cloud provider and the specific reference architecture size you plan to build. Support differs between AWS, GCP and Azure and between VM-based and Cloud Native Hybrid layouts, so check the toolkit documentation for your exact combination. Record the supported versions in your design document, and treat anything unlisted as a custom build that needs its own validation.
GitLab version and upgrade stops
Check that the GitLab version you deploy is one the toolkit targets and that your planned upgrade path passes through a required upgrade stop. Since GitLab 17.5 these fall at versions x.2, x.5, x.8 and x.11. Build the upgrade plan before go-live so that the first upgrade is not improvised on production data.
Terraform or OpenTofu compatibility
Pin the Terraform or OpenTofu version and the provider versions in your state configuration, then test them against the toolkit before you run an apply in your account. OpenTofu aims for feature parity with Terraform but does not guarantee compatibility with future Terraform releases, so a version bump on one side can break the other. Keep the tool version in source control next to the toolkit code.
Load test results against targets
The reference architecture sizes are defined by API requests per second, so a successful deployment does not prove that the environment meets its target. Run a load test against the RPS target for your user count, using the GitLab Performance Tool, and compare the results with the reference architecture. Keep the results as a baseline for later changes and for capacity reviews.
Geo for disaster recovery
The toolkit does not create a disaster recovery site on your behalf. If your recovery objectives need a second region, plan a Geo secondary site as a separate project, with its own network, storage and failover runbook. Geo requires the Premium or Ultimate tier, so confirm the licensing cost and the failover test schedule before you finalize the design.
Air-gapped and offline requirements
If your network cannot reach the public internet, the toolkit's default assumptions about package downloads, container images and external services will fail. Confirm which artifacts must come from an internal mirror, how security scanners and updates will be delivered, and who approves each transfer. Plan this before the first deployment, because retrofitting an offline network later usually means rebuilding parts of the environment.
How DeployOpen scopes and delivers a GitLab toolkit deployment
DeployOpen plans, builds, documents and supports self-hosted GitLab inside your own cloud accounts, data centers or air-gapped networks. For a GitLab Environment Toolkit deployment, we start from a written scope that states which reference architecture, cloud provider and toolkit version the build will use, then hand over a environment your team can operate.
How we scope
- Confirm user count, API request targets and CI load to select the matching reference architecture before any code is written.
- Record which cloud provider, network layout, identity provider and object storage backend the toolkit build will target.
- Agree in writing which toolkit limitations apply and which manual production steps sit inside or outside the fixed scope.
How we build
- Provision infrastructure with the toolkit's Terraform and Ansible code in version-controlled repositories your team can read.
- Complete the manual production steps the toolkit does not cover, such as TLS certificates, DNS, secrets handling and backup targets.
- Run a load test against the reference architecture targets and record results before the environment is accepted.
How we hand over
- Deliver runbooks for backup, restore, upgrade stops and scaling changes, written for the engineers who will operate GitLab.
- Document every deviation from the published reference architecture, including the reasons and the rollback path.
- Walk your team through a restore test and an upgrade rehearsal so the handover is checked, not only described.
How we support
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts.
- Ongoing support, upgrades and testing are available as a retainer, scoped to your environment and release schedule.
- Ask any partner to confirm in writing how upgrades across required upgrade stops and toolkit version changes are handled.

