Skip to content

Bluefly GitLab Exit Strategy

Decision document — September 23, 2026
GitLab subscription: A-S00141074
Current expiration date: December 15, 2026
Primary objectives: reduce recurring cost, preserve and independently back up source code, support agent-driven engineering, maintain a practical collaboration environment for the team, and avoid unnecessary custom infrastructure.

Saveable version: bluefly-gitlab-exit-strategy-2026.docx (produced in a generation sandbox; not tracked in this repository)

Executive decision

Bluefly should plan to leave paid GitLab rather than automatically renewing it, while preserving GitLab as a temporary safety net through the migration window.

The strongest target architecture is:

Forgejo as the primary forge on a small internet-hosted VM/VPS + separate CI/agent runners + the home NAS as a backup/mirror destination + a second encrypted off-site backup in an independent failure domain.

This is preferable to making the NAS in the house the sole production Git server. A NAS can be excellent infrastructure, but locating the only live forge, only backup, and possibly the build agents in the same building creates one large shared failure domain: power, ISP, router, theft, fire, water damage, NAS/controller failure, accidental deletion, credential compromise, or ransomware can affect everything at once.

The NAS should therefore be an asset in the resilience design, not the entire resilience design.

The recommendation also fits Bluefly's net-negative ownership rule. The forge should provide Git hosting, pull-request/change-review collaboration, APIs, webhooks, authentication and runner/workflow facilities upstream. Agents should consume those standard interfaces. Bluefly should not build another scheduler, agent runtime, workflow engine, Git service, or custom source-control management layer merely to leave GitLab.

There is also an important correction to the premise that Bluefly is necessarily “losing access to GitLab.” GitLab currently documents different expiration behavior depending on the offering. For GitLab.com, expiration removes the paid features while Free-tier functionality remains available. For GitLab Self-Managed, an expired paid license makes the instance read-only, but GitLab documents that the expired license can be removed to continue using Free-tier functionality. GitLab also confirms that manual renewal becomes available only within the 15-day period before expiration. citeturn0search0

For a December 15, 2026 expiration, that makes November 30, 2026 the beginning of the normal manual-renewal window. Bluefly should not use that date as the migration deadline. I would treat December 1 as the operational independence deadline and leave December 1–14 as contingency time.

Component Recommendation Why
Primary forge Forgejo Best architectural match for a lightweight open-source Git collaboration service
Primary location Small VPS/VM outside the house Team availability does not depend on residential power/ISP/NAS
NAS Backup + repository mirror + recovery destination Uses hardware Bluefly already owns without creating the only failure domain
Off-site backup Encrypted, versioned storage independent of both primary server and house Survives total site loss
CI Forgejo Actions with separate runners Uses upstream workflow/runner capability rather than custom orchestration; Forgejo provides a dedicated Actions runner model. citeturn0search1
Agents Git/SSH/API/webhooks plus least-privilege bot identities Keeps agents portable between forges
Immediate fallback GitLab Self-Managed Free Lowest conceptual migration if existing GitLab-specific CI/features prove too costly to convert before December
Long-term GitLab paid subscription Do not renew unless inventory proves a paid feature is economically indispensable The migration should be driven by actual dependencies, not inertia

What must actually be protected

The repository is only one part of what GitLab may currently hold.

A plain git clone preserves source history, but it does not by itself reproduce an operational software forge. The exit inventory needs to determine which of the following Bluefly currently depends on:

Asset class Migration treatment
Git commits, branches, tags and refs Mirror to new forge and independently archive
Git LFS Explicitly inventory, transfer and verify
Submodules Update URLs and credentials where necessary
Issues Migrate active data or preserve project export as historical archive
Merge requests Preserve active review work and historical context where importer supports it
Comments/discussions Determine whether live migration or archived history is sufficient
Labels and milestones Recreate/import where still operationally relevant
Wiki Export/migrate
Releases Recreate/import and retain release assets
Container registry Identify every image still used by development or production
Package registry Identify every downstream consumer
CI/CD pipelines Translate active pipelines; do not blindly reproduce obsolete ones
CI/CD secrets and variables Recreate securely, never by committing them to Git
Scheduled pipelines Recreate only where still required
Runners Replace with target-platform runners
Deploy keys Inventory, rotate and reissue
Personal/project/group tokens Replace and then revoke GitLab equivalents
Webhooks Point consumers at the new forge
Integrations Inventory production and development dependencies individually
Members/groups/permissions Map to target teams and least-privilege roles
Protected branches/tags Re-establish and test
Approval policies Determine whether they are truly required or were merely available
CODEOWNERS Preserve as repository content and verify target behavior
Pages/static sites Move deployment and hosting separately if used
Build artifacts Decide whether ephemeral or legally/operationally worth archiving
Security results Archive required historical results; replace active scanning through upstream tools
Terraform state or other GitLab-hosted state Treat as critical infrastructure data if used
Agent integrations Re-point to new Git/API identities rather than rebuilding the orchestration system

This distinction matters particularly if Bluefly decides to fall back to GitLab Free. GitLab says that when a GitLab.com subscription expires, paid functionality disappears but Free functionality remains. Consequently, anything that depends on a paid feature must be explicitly identified rather than assuming the account either “works” or “does not work.” citeturn0search0

The backup model

The desired recovery model should look like this:

Production forge → NAS backup/mirror → independent encrypted off-site backup

with CI runners outside the trust boundary of the forge itself.

I recommend four logically separate layers.

Primary application state. The forge has its Git repositories, database, LFS data, attachments/releases/packages where applicable, configuration and cryptographic/application secrets.

NAS recovery copy. The NAS receives automatic backups and, optionally, independent bare Git mirrors. Filesystem snapshots are useful here because they provide fast rollback from accidental deletion or a bad application upgrade.

Remote disaster-recovery copy. A second backup must live somewhere that cannot disappear with the house. It should have separate credentials from the forge and preferably versioning/immutability characteristics that make deletion from a compromised primary server difficult.

Restore environment. Bluefly periodically restores the backup onto a disposable machine or VM. This is essential because the useful measurement is not “the backup job returned success”; it is “we can reconstruct a working forge without GitLab.”

A repository mirror is useful but should not be mistaken for a full backup. Even a perfect Git mirror does not, on its own, reconstruct users, permissions, pull/merge-request discussions, application database state, runner configuration, secrets, webhooks, registry content or other forge metadata.

What happens if the house burns down?

Under the recommended architecture:

  1. The primary Forgejo service is still running outside the house.
  2. The NAS copy is lost.
  3. The second off-site backup remains available.
  4. A replacement NAS can later be populated from the primary service/off-site backups.
  5. Team collaboration continues while the physical recovery happens.

Under NAS-only hosting, by contrast, the team loses the forge and its local backup simultaneously unless another copy has already left the site.

That is the decisive reason I would not make the home NAS the only production system even though self-hosting Forgejo there is technically attractive.

Platform choices and tradeoffs

The correct comparison is not simply “which GitHub/GitLab clone has the longest feature list?” The decision should be driven by Bluefly's actual needs:

Git + code review + team permissions + issues + APIs + webhooks + automation runners + backups + agent access, with as little platform ownership as possible.

Forgejo

Recommendation: first choice.

Forgejo is the platform I would put through the primary migration proof-of-concept. The architectural attraction is that it provides the forge and automation interface without requiring Bluefly to operate something with GitLab's broader application footprint. Forgejo also has an upstream Actions/runner system, meaning Bluefly does not need to invent a CI scheduler merely to get automated builds after leaving GitLab. citeturn0search1

For an AI-heavy engineering organization, the critical point is not an “AI feature” checkbox. The forge needs to be automatable through Git and normal service interfaces while retaining human review and access controls. Agent-specific intelligence can live elsewhere; the source-control system should remain a reliable, boring source of truth.

Best use: long-term Bluefly primary forge.

Main migration cost: GitLab-specific CI/CD and paid collaboration features need to be inventoried and translated rather than assumed portable.

Gitea

Recommendation: retain as the closest comparison candidate during the lab test.

Architecturally, Gitea belongs in the same lightweight-forge category as Forgejo and therefore deserves a representative-repository test before committing the production migration.

I would not expand the project into a long Gitea-versus-Forgejo bake-off. Choose several difficult Bluefly repositories, test both against the same acceptance criteria, and choose the one that minimizes operational ownership while satisfying API, permissions, CI and backup requirements.

Because the final research pass did not capture current upstream Gitea documentation into the evidence set, its exact 2026 feature behavior should be verified against upstream documentation during that pilot rather than assumed from older product knowledge.

GitLab Self-Managed Free

Recommendation: excellent contingency/bridge; weaker default long-term choice.

If Bluefly discovers twenty production-critical .gitlab-ci.yml pipelines, extensive GitLab-specific deployment configuration, complicated permissions and substantial collaboration metadata, moving directly to another forge before December may create unnecessary risk.

In that case, self-managed GitLab Free can be an intermediate state: first eliminate the paid subscription dependency, then migrate the forge architecture deliberately.

This carries an important cost that does not show up as a license invoice: Bluefly becomes responsible for installation, upgrades, databases, background services, storage, backups, monitoring and security of GitLab itself. GitLab publishes substantial installation and infrastructure requirements for self-managed deployments, which supports treating it as the higher-operations option in this comparison. citeturn0search3

There is also a very important licensing-expiration detail. GitLab states that an expired Self-Managed paid license initially makes the instance read-only and locks operations such as pushes and issue creation. To continue on the Free tier, the expired license must be removed. citeturn0search0

Therefore a “just let the self-managed license expire” strategy should itself have a tested runbook.

Other open-source forges

OneDev and similar projects are worth knowing about, but I would treat them as secondary lab candidates, not migration targets until the primary Forgejo/Gitea/GitLab paths fail a requirement.

That is an application of Bluefly's ownership policy as much as a technology choice: every additional candidate increases migration testing, security review, operational knowledge and long-term decision surface.

There is little value in evaluating ten forges if one established upstream system covers the actual requirements.

Hosted proprietary services

GitHub and other hosted proprietary forges may be valuable as external mirrors, emergency collaboration targets, or public open-source distribution channels, but they should not be Bluefly's default primary system under the stated requirement that the core platform be open source and portable.

Using one as a secondary Git mirror is a very different architectural decision from making it the authoritative collaboration database.

Decision matrix

The following scores are Bluefly-specific architectural judgments, not vendor benchmark results. Five means best fit.

Candidate Open-source-first fit Migration fit Agent/API model Low operational burden Low cash-cost fit Recommendation
Forgejo self-hosted 5 4 5 4 5 Primary recommendation
Gitea self-hosted 5 4 5 4 5 Closest alternative; validate in pilot
GitLab Self-Managed Free 4 5 5 2 4 Migration bridge / fallback
OneDev or another smaller OSS forge 5 3 4 4 5 Investigate only if primary candidates fail
Proprietary hosted forge 1 4–5 5 5 3–5 Mirror/fallback, not preferred source of truth

The most important distinction is between software cost and ownership cost. GitLab Self-Managed Free may have zero license cost, but that does not make operating GitLab free. Conversely, running Forgejo on a small hosted machine introduces some infrastructure spend but may reduce administrative complexity.

Agent-ready architecture

Bluefly should avoid choosing a forge based on built-in generative-AI branding.

The better question is:

Can an agent safely interact with this repository and collaboration system using upstream interfaces while remaining subject to exactly the same review, permission and CI controls as a human engineer?

That leads to a much more durable design.

Agent control plane

Each autonomous or semi-autonomous agent should get an explicit service identity rather than sharing an administrator's token.

A typical engineering agent should be able to:

clone → create branch → commit → push → open change request → observe CI → respond to review

without automatically having permission to:

administer server → modify authentication → change runner configuration → change backups → read unrelated secrets → bypass protected branches → force-push protected branches

The agent integration layer should preferentially use, in order:

Git over SSH/HTTPS → upstream REST/API → webhooks → upstream CLI/MCP integration where one is maintained and trusted.

A missing convenience integration is not justification for Bluefly to create a parallel agent orchestration product.

Separate runners matter

Forgejo's upstream documentation provides an Actions runner model. citeturn0search1

I recommend treating runner infrastructure as a separate security zone from the forge itself.

Conceptually:

                  Internet
                     |
                 TLS / DNS
                     |
              +--------------+
              |   Forgejo    |
              |  application |
              +--------------+
                 |         |
          API/Git|         |backup
                 |         v
                 |      +------+
                 |      | NAS  |
                 |      +------+
                 |
        +--------+---------+
        |                  |
  +------------+     +------------+
  | CI runner  |     | Agent host |
  +------------+     +------------+
        |
   build/deploy

NAS / Forgejo backup
        |
        v
+----------------------+
| Independent encrypted|
| off-site backup      |
+----------------------+

This keeps a compromised build job or coding agent from automatically becoming a compromise of the server containing the authoritative repository and backup credentials.

The more autonomy Bluefly gives agents, the more important this separation becomes.

Migration, cutover, and disaster-recovery plan

The migration should begin by removing uncertainty, not by installing software.

Discovery and independent backup

By September 30, create a definitive inventory of:

  • namespaces/groups and repositories;
  • users and permissions;
  • active branches and protected branches;
  • LFS use and repository sizes;
  • active issues and merge requests;
  • releases and downloadable assets;
  • CI/CD pipelines and schedules;
  • runners;
  • variables/secrets;
  • deploy keys and tokens;
  • webhooks and third-party integrations;
  • container and package registries;
  • production deployment dependencies;
  • Pages/static sites;
  • GitLab paid features actually in use.

At the same time, make an independent copy of every Git repository outside GitLab.

For a repository where complete ref preservation is desired, the basic Git migration pattern is conceptually:

git clone --mirror OLD_REPOSITORY_URL
cd project.git
git remote set-url --push origin NEW_REPOSITORY_URL
git push --mirror

Use the mirror push only against a newly created target repository because a mirror operation is intended to make the target refs match the source. LFS data should be inventoried and transferred separately where used.

Do not treat that command as the whole migration; it only handles Git repository refs.

Build the new foundation

During the first half of October:

  1. Create the Forgejo production/staging environment.
  2. Configure a real database and persistent storage.
  3. Configure TLS and DNS.
  4. Configure outbound mail if team notifications need it.
  5. Create the backup destination on the NAS.
  6. Create the independent off-site backup.
  7. Stand up runner compute separately.
  8. Create team groups and least-privilege agent identities.
  9. Document recovery credentials somewhere that does not depend on Forgejo itself.

Forgejo's current documentation explicitly treats Actions runners as separately administered components, which aligns well with this separation. citeturn0search1

Pilot the hard repositories

Do not start by moving the easiest 100 repositories.

Move the repositories most likely to invalidate the architecture:

  • one ordinary application repository;
  • one large repository;
  • one using LFS;
  • one with significant issues/review history;
  • one with complicated GitLab CI;
  • one tied to deployment;
  • one actively used by coding agents.

A pilot succeeds only when the new system handles the difficult behaviors, not when git clone works.

Migrate collaboration state

Use the target platform's upstream GitLab migration/import functionality first for whatever assets it supports.

For anything the importer cannot preserve adequately, choose between:

Live migration — necessary when the team still actively works with the data.

Historical archive — appropriate for old issues, closed reviews and other records that need to remain available but do not need to become native live objects in the new forge.

This is important because perfect historical conversion can become a migration project of its own.

Bluefly should not build a permanent custom migration framework to preserve inactive metadata. Keep the GitLab export as historical evidence and selectively move active state unless a maintained upstream migration tool already solves the problem.

Convert the CI surface

The CI migration deserves its own workstream.

Do not assume .gitlab-ci.yml is the portable abstraction. Treat the actual build/test/deployment behavior as the specification.

For each active pipeline, answer:

Question Desired result
What triggers it? PR/change, push, release, schedule or manual
What does it build? Clearly reproducible command/container
What secrets does it require? Explicit new secret ownership
What artifacts does it publish? New registry/storage destination
What external system does it deploy? Integration re-pointed
Does the job still matter? Delete if obsolete
Does an upstream Action/tool already perform it? Consume that rather than custom-build

Forgejo provides its own Actions runner mechanism, so migration should consume that upstream facility instead of Bluefly creating another scheduler. citeturn0search1

Cut over before the subscription deadline

A realistic target calendar is:

Date Desired state
September 30 Complete inventory and independent Git backups
October 1–15 Forgejo lab/prod foundation and representative pilot
October 16–31 CI conversion, agent access and first complete restore test
November 1–15 Bulk repository and collaboration migration
November 16–30 Parallel verification; remove hidden GitLab dependencies
December 1–7 Final write freeze, final sync and production cutover
December 8–14 Contingency/rollback window
December 15 Paid GitLab no longer operationally required

GitLab's published subscription documentation confirms that a manual renewal is normally unavailable until the 15-day pre-expiration window and describes December 15 as an actual expiration boundary rather than a suggested planning date. citeturn0search0

Final freeze

At final cutover:

  1. Tell the team GitLab is entering read-only-by-policy mode.
  2. Stop merges and pushes to the old repositories.
  3. Perform final Git mirror synchronization.
  4. Complete any final issue/review data migration.
  5. Verify LFS and registry content.
  6. Change canonical repository URLs.
  7. Change CI/webhook integrations.
  8. Run builds and deployments.
  9. Test every production dependency.
  10. Have an agent execute the normal branch/change-request/CI lifecycle.
  11. Restore the platform from backup onto a clean machine.
  12. Only then revoke the old GitLab credentials and runners.

Completion criteria

Bluefly is completely off paid GitLab only when all of the following are true:

Acceptance test Required
All active repositories clone from new canonical forge Yes
Git commit/tag integrity checked Yes
Required LFS objects recoverable Yes
Team permissions tested using non-admin users Yes
Protected branches/change rules tested Yes
Active CI pipelines pass Yes
Production deployment succeeds without GitLab Yes
Container/package consumers no longer require GitLab Yes
GitLab webhook dependencies removed Yes
Agent can create branch/push/open review under restricted identity Yes
Agent cannot perform prohibited admin actions Yes
Off-site backup exists Yes
Clean restore from backup succeeds Yes
Final GitLab export archived Yes
Old GitLab tokens/deploy keys revoked after cutover Yes

The restore test is the strongest requirement in the table. Until it succeeds, Bluefly has moved its code but has not proved that it controls its recovery.

Questions, risks, and final recommendation

The following questions need definitive answers during inventory. They do not need to block the decision to begin migrating.

Subscription topology: Is A-S00141074 attached to GitLab.com SaaS or a Self-Managed instance? This changes what occurs on December 15. GitLab.com retains Free functionality after expiration; Self-Managed with an expired paid license becomes read-only until the expired license is removed or a new subscription is activated. citeturn0search0

Scale: How many repositories, groups, team members, active merge requests, active pipelines and runners are actually present?

GitLab specificity: Which paid or GitLab-specific capabilities are being actively used rather than merely available?

Data volume: How large are Git repositories, LFS objects, container images, packages, release assets and irreplaceable artifacts?

Production coupling: Does anything in production currently clone directly from GitLab, use GitLab package/container URLs, receive GitLab webhooks, rely on GitLab environment variables, or use GitLab as a deployment control plane?

CI portability: How many .gitlab-ci.yml files execute production-critical pipelines?

Agent permissions: Which agents should merely read repositories, which may push branches, which may open review requests, which may merge, and which—if any—are allowed to administer repository settings?

Availability target: Can the team tolerate the forge being unavailable whenever residential internet or power is down?

Recovery-point target: Is losing up to 24 hours of forge metadata acceptable, or should database/app backups happen more frequently?

Recovery-time target: After complete server loss, does the team need the forge back in one hour, four hours, or the following day?

Those answers determine sizing and backup frequency, but they do not substantially alter the recommended architecture.

Major risks

The largest technical risk is not repository migration. Git itself is highly portable. The larger risk is hidden platform dependency: CI secrets, registries, deployments, webhooks, authentication, issue history and GitLab-only features.

The largest self-hosting risk is concentrating too much responsibility on the NAS. Hosting the forge, runners and only backup on the same NAS reduces invoices while dramatically increasing correlated failure risk.

The largest agent risk is credential scope. An agent with server-administrator credentials is effectively part of the control plane. A better model makes an agent behave like a constrained engineer: branches and reviews by default, administrative operations only through a separate explicit mechanism.

The largest organizational risk is attempting to recreate GitLab internally. Bluefly needs a source-control and collaboration service; it does not need to become the maintainer of one.

Final architecture

                           BLUEFLY GIT PLATFORM

             Team                            AI agents
               |                                 |
               +---------- SSH / HTTPS / API ----+
                                |
                                v
                  +---------------------------+
                  |          Forgejo          |
                  |       Primary Forge       |
                  |     Internet-hosted VM    |
                  +---------------------------+
                      |                   |
                      |                   |
                 CI requests          scheduled
                      |                backups
                      v                   |
             +----------------+           v
             | Runner pool    |       +---------+
             | separate host  |       |   NAS   |
             +----------------+       | backup  |
                                      | mirror  |
                                      +---------+
                                           |
                                      encrypted
                                       backup
                                           |
                                           v
                                +---------------------+
                                | Independent offsite |
                                | recovery copy       |
                                +---------------------+

Bottom line

Do not renew GitLab by default. Do not move the entire risk onto the NAS either.

The strongest outcome is:

Forgejo becomes the authoritative collaboration forge.

A small internet-hosted machine keeps it available to the team independent of the house.

The NAS becomes a valuable local backup, mirror and restoration resource rather than a single point of failure.

A second encrypted off-site copy ensures that destruction or compromise of either location is survivable.

CI and coding agents run separately from the forge and interact through upstream Forgejo/Git/API/runner interfaces.

GitLab Self-Managed Free remains the escape hatch if the inventory reveals too much GitLab-specific CI or metadata to move safely before December. GitLab itself documents a more substantial self-managed installation footprint, so this should be considered the compatibility bridge rather than the default simplification path. citeturn0search3

Most importantly, December 15 is not the day to begin this project. GitLab's current subscription documentation confirms both the 15-day pre-expiration renewal window and the different post-expiration behavior for SaaS versus Self-Managed. citeturn0search0 The engineering target should be to have GitLab cease being a production dependency by December 1, 2026, leaving two weeks to discover mistakes while the existing system is still available.

Evidence and limitations

This research used current upstream GitLab and Forgejo documentation rather than third-party comparison sites for the highest-impact conclusions. GitLab's subscription documentation is the authority for renewal and expiration behavior. citeturn0search0 Forgejo's upstream runner documentation establishes the availability of an upstream Actions runner architecture. citeturn0search1 GitLab's own installation requirements inform the assessment of Self-Managed GitLab's operational footprint. citeturn0search3

One important item remains unverified in this version of the document: a complete item-by-item inventory of Bluefly's actual GitLab namespaces, projects, runners, registries, LFS usage, merge requests, CI variables, paid-feature dependencies and external integrations was not available in the evidence synthesized for this report. That inventory can materially affect migration effort and could elevate GitLab Self-Managed Free from “fallback” to “temporary bridge,” but it does not change the backup principle or the recommendation against relying on a single NAS/house as the sole failure domain.

Saved deliverable: bluefly-gitlab-exit-strategy-2026.docx (produced in a generation sandbox; not tracked in this repository)