Skip to content
Go back

Gitea vs Forgejo vs GitLab CE: Self-Hosted Git

· Updated:
By SumGuy 9 min read
Gitea vs Forgejo vs GitLab CE: Self-Hosted Git
Contents

Take a Breath. You Probably Don’t Need GitLab CE

Forgejo is the right default for solo developers and small teams, and GitLab CE only earns its keep once you have 50 or more developers who need CI/CD, a registry, and audit logging in one box.

Take a breath. Close those tabs. You’ve spent two hours reading four-year-old Reddit threads that are somehow still being argued about, and you still haven’t picked a self-hosted git platform.

Here’s the verdict up front. Forgejo is the right default for solo developers, home labs, and small teams: light footprint, community-governed, and it’ll outlive whatever drama hits its upstream next. Gitea is fine if you’re already on it and don’t care about fork politics. GitLab CE only earns its keep once you’ve got 50 or more developers who need unified CI/CD, a container registry, and audit logging in one box, plus the RAM budget to feed it.

Now let’s get into why any of this matters and how to actually run these things.

Why Self-Host Git At All?

GitHub is free, reliable, and everyone already has an account. So why bother running your own?

If you’re storing dotfiles and a couple of side projects, GitHub will serve you fine forever. If you’ve got a home lab, a small team, or a philosophical objection to renting your infrastructure from someone else, read on. You’ve got three serious contenders: GitLab CE is the kitchen sink, Gitea is the nimble workhorse, and Forgejo is Gitea’s community-governed fork that’s quietly becoming the safer long-term bet.


Gitea: The Lightweight Workhorse

Gitea forked from Gogs (a simpler git service) in 2016. It’s a single Go binary that runs comfortably in 512 MB of RAM by official recommendation, though a small instance idles closer to 50 to 100 MB in practice. Your Raspberry Pi handles it fine. Your $5 VPS handles it fine.

What you get:

What you don’t:

In 2022, that last point turned into a real problem. Gitea’s original maintainer set up a company to commercially back the project, and a chunk of long-time contributors worried the roadmap would drift toward features that needed beefier infrastructure and less community input. That friction is what produced Forgejo.


Forgejo: The Community Fork That Actually Matters

Forgejo hard-forked from Gitea in late 2022 and is governed by the Codeberg e.V. nonprofit instead of a company. No single vendor steers the roadmap.

At the code level, Forgejo and Gitea are nearly identical today: same ~50 to 100 MB footprint, same UI, same Docker image swap. What’s different is governance and a few features Forgejo has pushed further than upstream, including early work on ActivityPub federation, letting your instance interact with other Forgejo/Codeberg instances the way Mastodon servers talk to each other. It’s early, but it’s a genuinely interesting direction for decentralized code hosting that neither Gitea nor GitLab is chasing.

The practical reality: if you’re starting fresh, Forgejo is the safer pick. If you’re already on Gitea and happy, migrating later is painless, we’ll cover it below.


GitLab CE: The Full-Stack Freight Train

GitLab Community Edition is a full DevOps platform that happens to include git hosting: integrated CI/CD, container registry, security scanning (the good stuff is gated behind paid tiers, but the CE foundation is there), advanced LDAP/SAML SSO, Kubernetes integration, and audit logging.

What it costs:

GitLab CE is not a single binary. It’s a distributed system pretending to be an all-in-one tool, and if you don’t tune it, it will happily consume every byte of RAM on your server and stare at you blankly when you ask why.


Feature and Resource Comparison

FeatureGiteaForgejoGitLab CE
Git hosting
PR/MR workflows
CI/CDGitea Actions (built in)Forgejo Actions (built in)Full GitLab CI
Container/package registry✅ built in✅ built in✅ built in
Security scanning🟡 baseline in CE, full SAST is paid tiers
LDAP/SAML🟡 basic🟡 basic✅ mature
Federation (ActivityPub)🟡 in progress
Idle memory~50-100 MB~50-100 MB4 GB+
Recommended RAM512 MB512 MB8 GB+
Docker image size~100 MB~100 MB2 GB+
GovernanceCompany-backedNonprofit (Codeberg e.V.)Company-backed
Setup complexityLowLowHigh

Production Forgejo Setup (Docker Compose)

Here’s a production-ready Forgejo stack with PostgreSQL and a health check:

docker-compose.yml
services:
db:
image: postgres:16-alpine
container_name: forgejo-db
environment:
POSTGRES_DB: forgejo
POSTGRES_USER: forgejo
POSTGRES_PASSWORD: ${DB_PASSWORD:-change_me_please}
volumes:
- db_data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U forgejo"]
interval: 10s
timeout: 5s
retries: 5
forgejo:
image: codeberg.org/forgejo/forgejo:latest
container_name: forgejo
environment:
USER_UID: 1000
USER_GID: 1000
FORGEJO__database__DB_TYPE: postgres
FORGEJO__database__HOST: db:5432
FORGEJO__database__NAME: forgejo
FORGEJO__database__USER: forgejo
FORGEJO__database__PASSWD: ${DB_PASSWORD:-change_me_please}
FORGEJO__server__ROOT_URL: https://git.example.com/
FORGEJO__server__DOMAIN: git.example.com
FORGEJO__service__DISABLE_REGISTRATION: "false"
volumes:
- forgejo_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
depends_on:
db:
condition: service_healthy
restart: unless-stopped
volumes:
db_data:
forgejo_data:
Terminal window
export DB_PASSWORD=$(openssl rand -base64 16)
docker compose up -d
docker compose logs -f forgejo

The first user who registers becomes admin. Then set DISABLE_REGISTRATION: "true" to close signups, put a reverse proxy in front on 443, and open port 2222 for SSH cloning. Gitea’s Compose file is nearly identical, just swap the image to gitea/gitea:latest and the env prefix to GITEA__.

If you’re going the GitLab CE route instead, tune it or it will eat your server:

docker-compose.gitlab.yml
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
hostname: gitlab.example.com
restart: unless-stopped
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.example.com'
puma['worker_processes'] = 2
sidekiq['max_concurrency'] = 5
prometheus_monitoring['enable'] = false
gitlab_rails['env'] = {
'MALLOC_CONF' => 'dirty_decay_ms:1000,muzzy_decay_ms:1000'
}
ports:
- "80:80"
- "443:443"
- "2222:22"
volumes:
- ./gitlab-config:/etc/gitlab
- ./gitlab-logs:/var/log/gitlab
- ./gitlab-data:/var/opt/gitlab
shm_size: "256m"
deploy:
resources:
limits:
memory: 6g

Disabling Prometheus monitoring and capping Puma workers and Sidekiq concurrency is the difference between GitLab behaving on a modest server and GitLab quietly becoming the only thing your server does.

Pointing Existing Repos at Your New Server

Once it’s running, moving existing repos over is just a remote swap:

Terminal window
git remote add selfhosted http://your-server:3000/username/repo.git
# or replace origin entirely
git remote set-url origin http://your-server:3000/username/repo.git
git push selfhosted --all
git push selfhosted --tags

Migration Paths

Gitea to Forgejo: the easiest migration you’ll do all year. Stop the Gitea container, point the same data volume at a Forgejo container, start it. They share a database schema and read each other’s data without conversion.

GitHub or GitLab into Gitea or Forgejo: both ship a built-in migration tool. Go to “New Migration,” pick your source, and it imports repos, issues, PRs, and wikis. Not perfect for large orgs with heavy CI history, but genuinely smooth for personal projects and small teams.

Gitea or Forgejo into GitLab: manual work. There’s no equivalent import wizard, so plan on scripting issue recreation against GitLab’s API if you go this direction.


Which One Should You Actually Pick?

Pick Forgejo if: you’re running 1 to 50 developers, your server has under 4 GB of RAM, you want a single-binary ops-light solution, and you care about who controls the roadmap.

Pick Gitea if: you’re already on it and happy, or you want the identical lightweight product without following the fork’s governance drama.

Pick GitLab CE if: you have 50+ developers, the RAM budget to match, and you actually need SAST scanning, advanced audit logs, or enterprise SSO baked into the same box as your git hosting.


The Real Talk

Most self-hosters don’t need GitLab CE. They’ll spin up a cluster, allocate 16 GB of RAM, manage PostgreSQL backups, and use maybe 10% of what they installed. Forgejo or Gitea covers 90% of use cases at a fraction of the ops burden, and it boots in seconds on hardware that would make GitLab CE weep.

GitLab CE wins when you have a team large enough that unifying git, CI/CD, and registry into one system actually saves you from wiring disparate tools together. Otherwise you’re paying a complexity tax for features gathering dust.

Start with Forgejo if you’re not sure. It’s the lowest-risk entry point, and migrating up to GitLab later is always on the table. Your 2 AM self will thank you when your git platform boots in seconds and uses less RAM than your browser.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
Systemd Timers vs Cron: Scheduling That Doesn't Suck
Next Post
WireGuard vs OpenVPN 2026: It's Not Even Close

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts