# Migrating from Gitea to Forgejo

This page is the operational side of the move. If you are still deciding
whether to make it, the governance, licensing and feature comparison is on
[Forgejo vs Gitea](https://www.codey.ch/forgejo-vs-gitea/).

The short version: migrating from Gitea to Forgejo is an **upgrade in place**,
not an export and import. Forgejo takes over the existing database and data
directory. There is no repository re-import, no re-cloning by your developers,
and no change to remote URLs.

That makes it far less work than most platform migrations. It also means the
usual upgrade discipline applies, because you are running schema migrations
against your production database.

## Before you start

**Take a backup, and test restoring it.** This is the one step people skip and
regret. The migration runs database schema changes, and the rollback path is a
restore, not a downgrade (see the warning below). A backup you have not
restored at least once is a hypothesis.

**Check your version path.** Compatibility is not open-ended:

| From | To |
|---|---|
| Any Gitea version up to and including **v1.22.x** | **Forgejo v10.0.x** |
| Forgejo v10.0.x | Any newer Forgejo release |

So it is two steps, not one. Land on Forgejo v10.0.x first, confirm the
instance is healthy, then continue up the Forgejo release line. Gitea versions
newer than v1.22.x are past the point where the two codebases still line up:
Forgejo became a hard fork in early 2024 and has diverged since.

**Review your customizations.** If you have patched templates or added custom
CSS, diff your template directory against the stock one and note what you
changed. Customizations are the most common cause of a migration that
technically succeeds and visibly breaks.

**Check your Docker version** if you run in containers. Docker 20.10.6 or newer
avoids a class of problems that are hard to diagnose from the symptoms.

## The migration

**1. Flush the queues.**

```
forgejo manager flush-queues
```

Queues hold serialized data in a version-specific format, so anything still
pending when you swap versions may not be readable afterwards. If the command
times out, raise `--timeout` and run it again rather than moving on.

**2. Swap the binary or the container image.**

Replace the Gitea binary or image with Forgejo v10.0.x. Database migrations run
automatically on first start.

Forgejo keeps the binary named `gitea`, with symbolic links, precisely so that
existing systemd units, scripts and cron jobs keep working. You do not need to
rewrite your service files as part of this step.

**3. Verify.**

```
forgejo doctor check --all --log-file /tmp/doctor.log
```

Then open the web interface and check the things a script cannot: a repository
you care about, a pull request, a CI run, an SSH clone, and login through
whatever authentication source you use.

**4. Continue up the release line.**

Once v10.0.x is healthy, upgrade to a current Forgejo release. If an upgrade
spanning several versions fails, redo it one release series at a time to find
which one is unhappy.

## The one-way warning

**Downgrading is not supported and is actively prevented.** Once Forgejo has
migrated the database, version checks block an older binary from starting
against it. Going back means restoring your backup and losing anything written
since it was taken.

Plan the maintenance window accordingly: the decision point is before you start
Forgejo for the first time, not after.

## What usually goes wrong

- **Skipped or untested backups.** The failure mode is not "the migration
  broke", it is "the migration broke and we could not go back".
- **Custom templates.** They survive the upgrade and then render against
  changed markup. Diff first.
- **Version jumps.** Trying to go straight from an old Gitea to a current
  Forgejo instead of landing on v10.0.x first.
- **Pending queue items.** Skipping the flush and finding out later.
- **Authentication.** LDAP, OAuth and SSO configurations deserve an explicit
  test after the move, not an assumption.

## Where VSHN fits

We operate Forgejo in production and have run this path. Three ways to work
with us, depending on how much you want to keep:

**Keep running it yourself, with help for the move.** We plan the version path,
review your customizations, do a rehearsal against a restored copy of your
data, and stay on the call during the maintenance window.

**Hand over operations, keep your infrastructure.** We run the instance on your
cloud or on-premises platform: upgrades, backups, monitoring and incident
response, with the data staying where it is.

**Move to a managed instance.** [Codey](https://www.codey.ch) is a dedicated
Forgejo instance operated by VSHN in Switzerland from CHF 39 per month, with
Forgejo Actions CI/CD, package hosting and backups included. If you are already
planning a maintenance window to leave Gitea, moving to a managed instance
costs about the same effort as moving to a self-hosted one.

Not sure which fits? [Book a free migration assessment](https://vshn.cal.vs.hn/forgejo)
and we will map your current setup to a version path and a window.
