Comparison

Gitea vs Forgejo: Same Code, Different Owners

Disclosure: this post contains affiliate links (PartnerStack). If you buy through them I may earn a commission, at no extra cost to you.

Why this matters

A git server is infrastructure you set up once and then forget for years, which makes the choice of who maintains it more important than any feature on a comparison table. Gitea and Forgejo run almost the same software. They do not have the same owner, and that is the whole decision.

I moved a small instance between them twice in six months, with real repositories and real CI, to see what actually hurts.

The short version

Gitea is the original project, backed by Gitea Limited, which sells enterprise support and hosted services. Releases are frequent, the company is responsive, and there is a path to paying someone when something breaks badly.

Forgejo is a community fork created in 2022, governed by a non-profit (Codeberg e.V.) with a stated commitment to stay free software. It tracks Gitea closely, adds its own runner, and cannot be acquired in the way a company can.

What is actually identical

Worth saying plainly, because comparison posts usually inflate differences:

  • The web UI, repository browser, issue tracker and pull request flow
  • The API surface — clients and scripts written for one work on the other
  • The database schema lineage, which is why dumps restore across
  • Docker images, single-binary deployment, resource footprint (roughly 100–200 MB idle)
  • SSH and HTTP clone behaviour

A user who was not told which one they were using would not be able to tell.

Where they diverge

GiteaForgejo
GovernanceCompany (Gitea Ltd)Non-profit (Codeberg e.V.)
LicenceMITGPLv3+
Paid supportYesNo
Actions runneract_runnerForgejo Actions (own fork)
FederationNot a priorityActive experimentation
Release notesCompany blogCommunity, sometimes later
Migration from the otherSupportedSupported
Best fitTeam that wants a vendorUser who wants a guarantee

The licence row is the one people skip and later care about: MIT lets a fork go closed; GPLv3 does not.

Installing either one

Identical compose file, one image tag apart:

services:
  forge:
    image: codeberg.org/forgejo/forgejo:9   # or gitea/gitea:1.22
    container_name: forge
    restart: unless-stopped
    environment:
      USER_UID: "1000"
      USER_GID: "1000"
      FORGEJO__server__DOMAIN: git.example.com
      FORGEJO__server__ROOT_URL: https://git.example.com/
      FORGEJO__server__SSH_PORT: "2222"
    volumes:
      - ./forge-data:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"

For Gitea, swap the image and the FORGEJO__ prefixes for GITEA__. Everything else stays. That is how little separates them at install time.

How I tested

  • Host: Debian 13 VM, 2 vCPU, 4 GB RAM, both behind Caddy
  • Data: 14 repositories, two of them with active CI, about 800 MB total
  • Duration: Gitea for three months, Forgejo for three, same data migrated across
  • What I watched: upgrade behaviour, runner stability, memory, and how long it took to find an answer when something broke

Upgrades: where the real risk lives

Both upgrade by replacing the binary or image and restarting. Both run migrations on first boot. Neither is scary if you take a dump first.

The difference is what happens when a migration goes wrong. With Gitea, there is a company to file with. With Forgejo, there is a forum and an issue tracker. In three upgrades across both, nothing broke — but I took a dump before each one, and so should you:

docker exec -u git forge forgejo dump -c /data/gitea/conf/app.ini -f /data/backup.zip

That file is also your migration ticket between the two projects.

Moving between them

The documented path is a dump and restore, not a database copy:

  1. Take a full dump on the source instance.
  2. Start a fresh instance of the target on the same or newer minor version.
  3. Restore the dump into it.
  4. Update ROOT_URL and any absolute links in settings.
  5. Point DNS at the new box, keep the old one read-only for a week.

I did this once in each direction. Repositories, issues, users and keys came through. The only manual work was re-adding the SSH host key fingerprint to my known_hosts, which is expected.

The things nobody warns you about

Absolute URLs live in the database. Your ROOT_URL at install time gets baked into webhook payloads and some rendered links. Change domains later and you will find stragglers. Set the final domain before the first user signs up.

SSH on a non-standard port breaks clones for anyone who copies a URL without reading it. Both projects render the right port in the clone box, but people paste from GitHub out of habit and then wonder why it hangs.

SQLite is fine until it is not. A single user with a handful of repos will never notice. Two people pushing large repos at once can produce database is locked. Move to PostgreSQL before that becomes a mystery.

The runner is a separate service with its own update cadence, and a stale runner is the most common cause of “CI works locally, fails in the forge”.

Best for / Skip if

Forgejo is best for anyone who wants a self-hosted forge that cannot change licence or be bought, and who is comfortable with community support. If you are hosting other people’s code, the governance guarantee is worth something.

Skip Forgejo if you need a support contract, or you depend on a feature only Gitea Ltd ships.

Gitea is best for teams that want a vendor relationship, predictable release notes, and an upgrade path with someone accountable at the end of it.

Skip Gitea if the licence question is the reason you are self-hosting in the first place.

One practical note before you commit: whichever you install, the deployment steps are the Gitea walkthrough almost verbatim, and the dump-and-restore habit that makes this decision reversible is the same discipline as the backup guide. If those two pieces are in place, picking the “wrong” forge costs you an afternoon, not your history.

Alternatives

  • GitLab CE — far more features, far more RAM. Serious if you need CI runners, registries and review workflows in one place.
  • Bare git over SSH — no web UI, no issues, no CI. Genuinely enough for some people.
  • Codeberg — hosted by the same non-profit behind Forgejo, if you would rather not run it at all.

Verdict

I stayed on Forgejo. The software is the same quality, the dump-and-restore path means I am not locked in either direction, and the governance guarantee costs me nothing today. If I were running this for a company that needed someone to call during an incident, I would run Gitea and pay for support without hesitating.

The migration takes an afternoon. Pick the owner you want to depend on, not the feature list — the features are the same.

References

Tools used in this post

FAQ

Can I migrate from Gitea to Forgejo without losing data?

Yes. Forgejo reads a Gitea dump, so the documented path is to take a full dump from Gitea, restore it into a Forgejo instance of the same or newer minor version, then point your DNS at the new box. Repositories, issues, users and SSH keys come across; settings that reference absolute URLs need updating.

Do the two projects have different features today?

The core forge — repositories, issues, pull requests, actions, packages — is the same codebase lineage and behaves nearly identically. Forgejo has diverged on governance, on the actions runner, and on federation experiments. For day-to-day use, most people would not notice the difference.

Which one is safer for a long-term install?

That depends on what you mean by safe. Forgejo is governed by a non-profit and cannot be sold; Gitea is backed by a company and can offer paid support and enterprise features. If the risk you worry about is a licence change, Forgejo is the answer; if it is having nobody to call, Gitea is.

Does either one need a database server?

No. Both run happily on SQLite for a single-user or small-team instance. Switch to PostgreSQL before you have many concurrent users, because SQLite locking under parallel pushes is where it starts to hurt.

Henry Xiang

I keep self-hosted services alive for a living — backups, docs, monitoring, the boring parts that break at 3am. Everything here runs on my own hardware first.