How to Customize Gitea Settings Programmatically: 3 Methods Explained
You can customize Gitea settings programmatically through the ConfigProvider interface for direct file manipulation, REST API endpoints for runtime changes, or the admin API for database-backed configuration values.
Gitea's configuration system is built on a layered, INI-based architecture that supports both file-based modifications and runtime updates. According to the go-gitea/gitea source code, administrators can automate configuration changes using Go's native setting package or external REST calls without requiring manual UI interaction.
Understanding the ConfigProvider Architecture
At the core of Gitea's configuration system is the ConfigProvider interface defined in modules/setting/config_provider.go. This abstraction wraps INI file operations and exposes methods for reading and mutating settings programmatically.
The ConfigProvider Interface
The interface defines the contract for all configuration operations:
type ConfigProvider interface {
Section(string) ConfigSection // retrieve a section
Save() error // persist changes
DisableSaving() // make the provider read-only
PrepareSaving() (ConfigProvider, error) // reload clean config for safe saving
}
When Gitea starts, cmd/web.go invokes setting.NewConfigProviderFromFile(appIniPath) (implemented in the same file), which parses app.ini or a custom file supplied with the -c flag. The provider is stored globally in setting.CfgProvider.
Reading and Writing Values
To access settings programmatically, obtain a section via provider.Section("section_name"), then manipulate keys using ConfigSection.Key("key"). The returned ConfigKey supports type-safe getters like MustString, MustBool, and MustInt, while SetValue(v) updates values in memory.
The implementation in modules/setting/config_provider.go (lines 58-63) shows these operations:
func (s *iniConfigSection) Key(key string) ConfigKey { return s.sec.Key(key) }
func (s *iniConfigSection) DeleteKey(key string) { s.sec.DeleteKey(key) }
Method 1: Direct ConfigProvider Manipulation
For deployment scripts or external Go tools that need to modify app.ini directly, use the NewConfigProviderFromFile constructor and persist changes with Save().
Modifying Configuration Sections
Load the provider, retrieve sections, and update keys:
package main
import (
"log"
"code.gitea.io/gitea/modules/setting"
)
func main() {
// Load the existing configuration file
provider, err := setting.NewConfigProviderFromFile("custom/app.ini")
if err != nil {
log.Fatalf("load config: %v", err)
}
// Change a global UI setting
uiSec := provider.Section("ui")
uiSec.Key("DEFAULT_THEME").SetValue("gitea-dark")
// Enable a feature flag
featureSec := provider.Section("service")
featureSec.Key("ENABLE_NOTIFY_MAIL").SetValue("true")
// Persist changes
if err := provider.Save(); err != nil {
log.Fatalf("save config: %v", err)
}
}
Persistence and Permissions
The Save() method (lines 66-93 of config_provider.go) writes the modified INI back to disk and ensures file permissions are tightened for security. If the provider was created from a temporary source, use SaveTo(filename) instead.
Method 2: REST API for Runtime Configuration
Gitea exposes REST endpoints that allow external clients to read or modify settings without file system access, implemented in routers/api/v1/settings/settings.go and routers/api/v1/admin/config.go (routed through routers/api/v1/api.go at lines 958-962).
Global System Settings
Access global UI, API, repository, and attachment settings via endpoints like GET /settings/ui or GET /settings/api. Changes made through these endpoints read directly from the loaded setting structures and reflect immediately in API responses.
Per-User Settings
User-specific preferences are handled in routers/api/v1/user/settings.go. Authenticated users can update their settings via PATCH /user/settings:
USER_TOKEN="USER_ACCESS_TOKEN"
curl -X PATCH "https://git.example.com/api/v1/user/settings" \
-H "Authorization: token $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"theme": "gitea-dark"}'
Admin Configuration Endpoint
For system-wide changes while the server is running, use the admin API with an admin token:
TOKEN="YOUR_ADMIN_TOKEN"
curl -X PATCH "https://git.example.com/api/v1/admin/config" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ui": {"DEFAULT_THEME": "gitea-dark"}}'
Method 3: Database-Backed Settings
Certain configuration options have migrated from app.ini to the database and are managed through the admin panel or admin API. The setting.deprecatedSettingDB function (lines 44-48 of config_provider.go) handles the deprecation warnings.
When a key is present in app.ini but managed in the database, it is ignored. Update these values via the admin API (/admin/config) or the web UI at Configuration → Settings.
Summary
- ConfigProvider Interface: Use
modules/setting/config_provider.goto load, modify, and saveapp.iniprogrammatically from Go code. - REST API: Call
/settings/*,/user/settings, or/admin/configendpoints to change settings at runtime without file access. - Database Storage: Modern Gitea versions store some settings in the database; modify these via the admin API rather than the INI file.
- File Permissions: The
Save()method automatically tightens permissions when writing configuration files. - Runtime Reflection: API endpoints read from the same
settingstructures populated at startup, ensuring consistency between file and API-based configuration.
Frequently Asked Questions
Can I change Gitea settings without restarting the server?
Yes. Use the REST API endpoints (/admin/config for system settings or /user/settings for personal preferences) to modify values at runtime. However, some low-level settings in app.ini require a restart to take effect because they are loaded into global variables during initialization in modules/setting/setting.go.
What happens if I edit app.ini settings that have moved to the database?
Gitea ignores INI values for settings that have been migrated to the database. The setting.deprecatedSettingDB function logs a warning when such keys are detected. You must update these values via the admin panel or the admin API (/admin/config) instead of editing the configuration file.
Is the ConfigProvider safe for concurrent modifications?
The ConfigProvider interface does not guarantee thread safety for concurrent writes. For automation scripts, ensure only one process calls Save() at a time. For runtime modifications, prefer the REST API which handles concurrency through Gitea's HTTP request handlers.
How do I access configuration values in an external tool?
Import code.gitea.io/gitea/modules/setting and use NewConfigProviderFromFile() to load the configuration outside of Gitea itself. This approach is useful for deployment automation that needs to verify or modify settings before starting the Gitea process.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →