Markus Unterwaditzer’s guide to migrating from GitHub to Codeberg frames the whole process as something a lazy person can do, which turns out to be a useful diagnostic lens. Laziness is a reasonable proxy for dependency. If something is hard to move, you have a lock-in problem. If it is easy, you don’t.
Most developers who have thought about leaving GitHub assume the migration will be painful. The actual experience is split: the git parts are trivially portable, the CI parts are annoying but manageable, and the social and ecosystem parts are where you run into genuine trade-offs.
The git layer is genuinely portable
Git was designed to be location-agnostic. A repository is a repository regardless of what server hosts it, and adding a second remote is trivial:
# Dual-push to both GitHub and Codeberg simultaneously
git remote set-url --add --push origin https://codeberg.org/username/repo.git
With that one command, every git push origin replicates to both platforms. You don’t need to update collaborators’ remotes, modify deploy keys, or change any local tooling. The code exists in two places at no additional cost.
Codeberg runs Forgejo, a community-governed hard fork of Gitea that split in late 2022 after the Gitea project reorganized around a for-profit corporate structure. The fork is governed by the Forgejo project committee and has been on a distinct development path since. It supports full repository import through a web UI at codeberg.org/repo/migrate, which pulls in not just the git history but issues, pull requests, labels, milestones, and releases from GitHub via the official API. This means timestamps are preserved and pagination is handled correctly, which matters for projects with years of issue history.
For most personal projects and smaller libraries, code migration plus issue import is the complete migration. The technical overhead is an afternoon.
Where the friction lives: CI and workflow files
GitHub Actions has become so ubiquitous that developers often stop thinking of it as a GitHub-specific technology. It’s just “how CI works” for a large fraction of open-source projects.
Forgejo Actions, Codeberg’s CI system, made a deliberate design choice to be syntax-compatible with GitHub Actions. A typical workflow file requires only a single change to run on both platforms:
on: [push, pull_request]
jobs:
test:
runs-on: docker # GitHub uses ubuntu-latest; Forgejo uses docker
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --all-features
Copy the file from .github/workflows/ to .forgejo/workflows/, change the runs-on label, and most pipelines work. The Forgejo project explicitly designed this compatibility to lower the migration barrier, which is both a pragmatic engineering choice and a statement about values: they want it to be cheap to leave GitHub, so they built the on-ramp accordingly.
This contrasts sharply with sourcehut, which rejects the GitHub Actions model entirely in favor of email-based patch workflows modeled on the Linux kernel development process. Sourcehut’s approach is ideologically coherent and technically interesting, but it requires contributors to change how they work. Forgejo’s compatibility approach means contributors need to change almost nothing.
The caveat on Codeberg’s hosted runners is real: capacity is limited. Projects with heavy CI workloads may encounter queue times or runner constraints. Codeberg supports self-hosted runners, and Woodpecker CI is a popular alternative that integrates natively with Forgejo and lets you sidestep the Actions syntax entirely for complex pipelines.
The ecosystem layer is where it gets honest
The harder migration involves the invisible accumulation of integrations around an active GitHub repository.
Dependabot is GitHub-specific. CodeQL is GitHub-specific. GitHub’s advanced cross-repository code search is GitHub-specific. Many GitHub Actions marketplace actions have no direct Forgejo equivalent. For each of these, there is a workable alternative, but you have to go find it and configure it yourself rather than clicking a checkbox.
For dependency updates, Renovate Bot works across GitHub, Forgejo, GitLab, and Bitbucket, and is arguably more configurable than Dependabot. For static analysis, most tools run fine in CI on any platform; the GitHub-specific parts are usually the UI integrations, not the analysis engines themselves. For code search, tools like grep.app index public repositories regardless of hosting platform.
The social graph is the part with no clean technical solution. GitHub has roughly a hundred million registered users. Codeberg has hundreds of thousands. A project hosted exclusively on Codeberg reaches a smaller discovery audience, earns fewer organic stars from passersby, and attracts fewer contributions from developers who find projects through GitHub’s explore and trending pages. For a library with a stable, known user base this barely matters. For a new project trying to build community from scratch, it matters considerably.
The “lazy” filter as dependency audit
The reason the lazy-migration framing is useful is that it forces precision about what you actually depend on. If a step can be done lazily, your workflow has low coupling to the platform. If a step is genuinely hard, you’ve discovered a real dependency.
For personal projects and single-maintainer tools, the migration is genuinely lazy. The git history moves cleanly. Issues migrate through the web UI. A CI file needs one line changed. The result is a project hosted on infrastructure that is EU-based, GDPR-compliant, non-profit governed under German association law, and not subject to Microsoft’s content policies or questions about training data use.
The Software Freedom Conservancy’s Give Up GitHub campaign has been making the structural argument since 2022: concentrating critical FOSS infrastructure under a single for-profit corporation creates systemic risk, and GitHub Copilot’s training on public repositories without explicit contributor consent was the moment that made the argument concrete for many people. The campaign has been effective at making the question explicit for projects that hadn’t thought about it, even among maintainers who ultimately chose to stay.
Forgejo federation: the long-term differentiator
Forgejo’s most technically ambitious project is ActivityPub federation. The goal is to allow repositories on different Forgejo instances to interact across instance boundaries: fork a repository from one instance to another, comment on issues from a different instance, receive pull requests from contributors who have no account on your instance.
This is experimental and incomplete as of early 2025, but the design goal addresses the core problem with the current fragmented hosting landscape. Even if you move to Codeberg or self-host Forgejo, you still face a coordination problem: contributors need accounts on your platform, discovery requires being on the platform where people look, and the network effect stays concentrated elsewhere.
Federation shifts the economics without requiring everyone to be on the same server. A contributor on one Forgejo instance could interact with a project on another without creating an additional account. The network effect becomes distributed rather than concentrated in a single corporate-owned node. This is the same architectural bet that Mastodon made against Twitter, applied to software development infrastructure. The technical foundation is sound; the social adoption problem is, as always, harder than the technical one.
The tea CLI, Forgejo’s equivalent of GitHub’s gh, handles repository management and scripting from the command line. The Forgejo migration API at POST /api/v1/repos/migrate supports programmatic bulk migration for organizations with many repositories.
The practical picture
For a developer with a collection of personal projects, moving to Codeberg has low cost and low risk. Dual-hosting during a transition period is free beyond a second push destination, and it lets you evaluate Codeberg’s CI, issue tracker, and Pages hosting before committing fully.
For projects with active contributor communities, the honest answer is that some friction is real and the GitHub network effect matters. The migration path is well-documented and technically clear, but the decision involves trade-offs that depend on what the project is and who contributes to it.
What the lazy-migration framing gets right is the emphasis on separating the technical question from the values question. The technical barriers to leaving GitHub are lower than most developers assume, substantially lower than they were three years ago. The barriers that remain are social and ecosystem-based. That is a reasonable and even encouraging state of affairs for infrastructure built on top of a protocol that was designed from the start to have no single owner.