GoBlogger

Simple blogging. Single-binary deployment, easy for everyone.


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:

  1. custom/ (your customizations) — highest priority
  2. theme/ (optional local overrides; avoid touching when possible)
  3. 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 use theme/ 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:

  1. Find the file in theme/ you want to change.
  2. Copy it into custom/ with the same relative path.
  3. 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

  1. Use custom/css/ for CSS changes — never edited by updates
  2. Use custom/templates/ for template overrides — copy from theme/templates/ and keep exact paths/names
  3. Use custom/locales/ and custom/fonts/ for content assets — locale override filenames must match exactly (e.g. en.json)
  4. 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 in custom/ 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:

  1. Open /admin/theme.
  2. Choose Font family.
  3. Save.

The same setting can be managed via .env using BLOG_FONT_FAMILY:

  • atkinson_hyperlegible_mono
  • atkinson_hyperlegible_next
  • ia_writer_duos
  • monospace
  • os_sans
  • os_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:

  1. Open /admin/theme
  2. Add CSS in the "Site Custom CSS" or "Admin Custom CSS" fields
  3. 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/themeSite 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.css for minor spacing, typography, or layout adjustments
  • Custom font: Add @font-face to custom/css/fonts-override.css and place font files in custom/fonts/
  • Color adjustments: Use the admin interface to set custom background/text/accent colors
  • Navigation changes: Place a customized templates/base.html only in custom/templates/ if the default doesn't meet your needs
  • Localization tweaks: Override specific strings in custom/locales/en.json without 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 touching custom/
  • 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