diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index a9f41d0d01..98199fec97 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -28,6 +28,7 @@ import (
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
+	forgejo_services "code.gitea.io/gitea/services/forgejo"
 
 	"xorm.io/xorm"
 	"xorm.io/xorm/names"
@@ -554,6 +555,7 @@ func Migrate(x *xorm.Engine) error {
 		return fmt.Errorf("sync: %w", err)
 	}
 
+	var previousVersion int64
 	currentVersion := &Version{ID: 1}
 	has, err := x.Get(currentVersion)
 	if err != nil {
@@ -567,6 +569,8 @@ func Migrate(x *xorm.Engine) error {
 		if _, err = x.InsertOne(currentVersion); err != nil {
 			return fmt.Errorf("insert: %w", err)
 		}
+	} else {
+		previousVersion = currentVersion.Version
 	}
 
 	v := currentVersion.Version
@@ -595,6 +599,10 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
 		}
 	}
 
+	if err := forgejo_services.PreMigrationSanityChecks(x, previousVersion, setting.CfgProvider); err != nil {
+		return err
+	}
+
 	// Migrate
 	for i, m := range migrations[v-minDBVersion:] {
 		log.Info("Migration[%d]: %s", v+int64(i), m.Description())
diff --git a/services/forgejo/main_test.go b/services/forgejo/main_test.go
new file mode 100644
index 0000000000..d3d7d04766
--- /dev/null
+++ b/services/forgejo/main_test.go
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+
+package forgejo
+
+import (
+	"path/filepath"
+	"testing"
+
+	"code.gitea.io/gitea/models/unittest"
+
+	_ "code.gitea.io/gitea/models"
+)
+
+func TestMain(m *testing.M) {
+	unittest.MainTest(m, &unittest.TestOptions{
+		GiteaRootPath: filepath.Join("..", ".."),
+	})
+}
diff --git a/services/forgejo/sanity.go b/services/forgejo/sanity.go
new file mode 100644
index 0000000000..0ca85c8406
--- /dev/null
+++ b/services/forgejo/sanity.go
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+
+package forgejo
+
+import (
+	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/modules/log"
+	"code.gitea.io/gitea/modules/setting"
+)
+
+var (
+	ForgejoV5DatabaseVersion = int64(260)
+	ForgejoV4DatabaseVersion = int64(244)
+)
+
+var logFatal = log.Fatal
+
+func fatal(err error) error {
+	logFatal("%v", err)
+	return err
+}
+
+func PreMigrationSanityChecks(e db.Engine, dbVersion int64, cfg setting.ConfigProvider) error {
+	return nil
+}
diff --git a/services/forgejo/sanity_test.go b/services/forgejo/sanity_test.go
new file mode 100644
index 0000000000..29ed3bbfff
--- /dev/null
+++ b/services/forgejo/sanity_test.go
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+
+package forgejo
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unittest"
+	"code.gitea.io/gitea/modules/setting"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestForgejo_PreMigrationSanityChecks(t *testing.T) {
+	assert.NoError(t, unittest.PrepareTestDatabase())
+	ctx := db.DefaultContext
+	e := db.GetEngine(ctx)
+
+	assert.NoError(t, PreMigrationSanityChecks(e, ForgejoV4DatabaseVersion, configFixture(t, "")))
+}
+
+func configFixture(t *testing.T, content string) setting.ConfigProvider {
+	config := filepath.Join(t.TempDir(), "app.ini")
+	assert.NoError(t, os.WriteFile(config, []byte(content), 0o777))
+	cfg, err := setting.NewConfigProviderFromFile(config)
+	assert.NoError(t, err)
+	return cfg
+}