Customising GoBlogger
Cleanly customize themes, styles, and templates without update pain.
Customization should be update-safe. GoBlogger uses a cascading override system to keep the built-in theme updatable while protecting your customizations.
Cascading Override System
When loading assets, templates, or locales, GoBlogger checks in this order:
custom/(your customizations) — highest prioritytheme/(optional local overrides; avoid touching when possible)- embedded built-in defaults (
default_theme) — lowest priority
This means:
- Updates are safe: The embedded built-in defaults (
default_theme) can be updated without touching your custom files - Your changes stick: Files in
custom/are never overwritten - Recommended workflow: Put your changes in
custom/first, and usetheme/only when you really need that middle layer
The custom/ directory is created automatically on startup if it doesn't exist.
No app restart is required for normal template/asset/locale override files. They are read from disk on request.
Directory Structure
Overrides are path-based. GoBlogger only overrides files when the file in custom/ has the exact same relative path and filename as the one being loaded.
Recommended workflow:
- Find the file in
theme/you want to change. - Copy it into
custom/with the same relative path. - Edit the copy in
custom/.
If the name or path does not match exactly, the file is ignored for override purposes.
custom/
├── css/
│ ├── custom.css (site custom styles)
│ └── admin-custom.css (admin custom styles)
├── fonts/
│ └── ... (your custom font files)
├── templates/
│ ├── base.html
│ ├── index.html
│ ├── admin/
│ │ └── base.html
│ └── ...
└── locales/
├── en.json
├── de.json
└── ...
default_theme is embedded in the binary and acts as the fallback base layer. It is not a visible folder in your project.
theme/ is an optional middle override layer. In most setups, you should avoid editing it and keep customizations in custom/.
Strategy for Safe Customization
- Use
custom/css/for CSS changes — never edited by updates - Use
custom/templates/for template overrides — copy fromtheme/templates/and keep exact paths/names - Use
custom/locales/andcustom/fonts/for content assets — locale override filenames must match exactly (e.g.en.json) - Use the admin interface for quick CSS changes — automatically saved to
custom/css/
When Changes Apply
- Templates, assets, and locales: Loaded from disk via the override chain on request, so a server restart is usually not required.
- Browser refresh is still required: You must reload the page to see changes.
- Production asset caching:
/assets/*is served with long-lived immutable cache headers, so CSS/font/image changes may require a hard refresh (or cache-busting URL) before the browser fetches the new file. - Dev auto-reload scope: Live-reload events watch
theme/and content files. Changes incustom/can apply on the next request, but may not always trigger automatic browser reload by themselves.
Changing the active font
Use the theme settings page:
- Open
/admin/theme. - Choose Font family.
- Save.
The same setting can be managed via .env using BLOG_FONT_FAMILY:
atkinson_hyperlegible_monoatkinson_hyperlegible_nextia_writer_duosmonospaceos_sansos_serif
Default: atkinson_hyperlegible_next.
In the default theme, both Atkinson options (atkinson_hyperlegible_next and atkinson_hyperlegible_mono) use a default text size of 20px.
Customizing CSS via Admin
The easiest way to add custom styles is through the admin interface:
- Open
/admin/theme - Add CSS in the "Site Custom CSS" or "Admin Custom CSS" fields
- Save
These changes are automatically saved to:
- Site CSS:
custom/css/custom.css - Admin CSS:
custom/css/admin-custom.css
These files are never overwritten during updates.
Color mode and custom colors
- Color mode: Choose Light, Dark, or Auto separately for the site and the admin interface. Auto follows the user's system preference.
- Site custom colors: Set custom background, text, accent border, and accent background colors independently for light and dark modes. Use the reset option to clear custom values and revert to the default theme colors.
- Custom CSS: Add custom CSS for the public site and the admin panel separately via the admin interface. Changes are saved to
custom/css/.
Overriding the font with CSS
If you want to force a different font than the configured theme setting, add CSS either:
- Via admin:
/admin/theme→ Site Custom CSS - File-based: Create
custom/css/fonts-override.css
Example (custom/css/fonts-override.css):
@font-face {
font-family: "My Site Font";
src: url("/assets/fonts/my-site-font.woff2") format("woff2");
font-style: normal;
font-weight: 400;
font-display: swap;
}
body,
button,
input,
select,
textarea,
.site-title {
font-family: "My Site Font", sans-serif;
}
Note: Prefer putting font files in custom/fonts/ to keep everything update-safe and in one place.
Overriding Templates
To override a template (e.g., templates/base.html), copy it from theme/templates/base.html to custom/templates/base.html and keep the same directory structure:
custom/templates/
├── base.html (your custom base template)
├── index.html (your custom index template)
└── admin/
└── base.html (your custom admin base)
GoBlogger will use your version instead of the default only when the path/name matches exactly. This is powerful but requires maintenance—if the built-in template changes, your override may need updates.
Overriding Translations
To customize translations, copy locale files from theme/locales/ to custom/locales/ with the exact same filename:
custom/locales/
├── en.json (your custom English strings)
└── de.json (your custom German strings)
Your custom translations will override the defaults only when the locale filename matches exactly.
Best Practices
- Prefer CSS overrides over template overrides — CSS in
custom/css/requires minimal maintenance - Keep overrides focused and small — easier to maintain across theme updates
- Keep admin CSS separate from site CSS — helps avoid side effects and debugging confusion
- Comment your CSS — future you will appreciate knowing why a rule exists
- Test in both light and dark modes — if you customize colors
- Only override what's necessary — rely on the built-in theme where possible
Example Use Cases
- Quick style tweaks: Use
custom/css/custom.cssfor minor spacing, typography, or layout adjustments - Custom font: Add
@font-facetocustom/css/fonts-override.cssand place font files incustom/fonts/ - Color adjustments: Use the admin interface to set custom background/text/accent colors
- Navigation changes: Place a customized
templates/base.htmlonly incustom/templates/if the default doesn't meet your needs - Localization tweaks: Override specific strings in
custom/locales/en.jsonwithout copying the entire file
Why This System?
Previous approaches required choosing between:
- Copying the entire theme: Caused merge conflicts on every update
- Editing in-place: Customizations were lost on updates
With the cascading system, you get the best of both:
- Updates work safely: Embedded built-in defaults (
default_theme) can evolve without touchingcustom/ - Your changes persist: Files in
custom/are never modified by updates - Flexibility: Override just what you need, and leave
theme/untouched unless you have a specific reason