Self-hosted start pages tend to look interchangeable from a distance: a grid of links, a search box, perhaps some status cards, and a convenient place to start a browser session. Their configuration models are much less interchangeable.

That distinction matters if the dashboard itself is treated as infrastructure. A start page containing fifty or a hundred carefully grouped links is already a useful data set. Once it also contains service credentials, status widgets, Docker discovery rules, layout choices, icons, tabs, permissions and user-specific state, moving to another application can become a migration project rather than a configuration change.

I recently compared Homepage with my own gobookmarks. The interesting result was that the links are highly transplantable while the dashboard behaviour is not. Looking at several other projects makes the reason clearer: these applications are solving overlapping, but not identical, problems.

This article compares:

The important question is not simply which one has the longest feature list. It is: what is the application’s source of truth, and how much of that source of truth can be carried somewhere else?

The portability spectrum

At a high level these projects sit on a spectrum between configuration-as-data and application-managed state.

ProjectPrimary modelMain source of truthRich service integrationsPortability of plain links
gobookmarksbookmark/start-page hierarchysmall text format, optionally Git-backedLowVery high
Homerstatic launcherYAMLLow to mediumVery high
Homepageservice dashboard and launcherseveral YAML files and discovery metadataVery highVery high
Dashyconfigurable personal dashboardYAML, also editable through the UIHighVery high
Glanceinformation/feed dashboardYAMLHigh, but widget-orientedHigh for bookmark widgets
Flameapp and bookmark launcherSQLite-backed application stateMediumHigh conceptually
Heimdallapplication launcherapplication database/UIMedium to high through enhanced appsHigh conceptually
Homarrintegrated multi-user dashboardapplication-managed database/UIHighHigh conceptually, lower mechanically

“Portability of plain links” deliberately ignores styling, credentials and application-specific widget configuration. Every project can represent a URL somehow. The difference is whether that URL lives in a simple file that can be transformed mechanically, or is one record in a richer application model.

Homepage: configuration as a dashboard description

Homepage is one of the richer configuration-as-code choices. It separates major concerns into files such as:

  • services.yaml
  • bookmarks.yaml
  • widgets.yaml
  • settings.yaml

A basic bookmark group is structurally simple:

 1- Developer:
 2    - GitHub:
 3        - abbr: GH
 4          href: https://github.com/
 5
 6- Social:
 7    - Reddit:
 8        - icon: reddit.png
 9          href: https://reddit.com/
10          description: The front page of the internet

Services use a similar grouping model but can add considerably more behaviour:

1- Media:
2    - Jellyfin:
3        icon: jellyfin.png
4        href: https://jellyfin.example.com/
5        description: Movies and television
6        widget:
7          type: jellyfin
8          url: https://jellyfin.example.com/
9          key: ${JELLYFIN_API_KEY}

This is where the meaning of “dashboard” starts to diverge from “bookmarks”. The href and display name are generic. The Jellyfin widget, API key, supported fields, highlighting rules and other integration settings belong specifically to Homepage’s model.

Homepage also allows layout policy to be declared separately. Groups can be assigned to tabs, arranged as rows or columns, collapsed, shown with icons only, or discovered from Docker and Kubernetes metadata.

That makes Homepage’s configuration very portable within Homepage: it is text, it can be version controlled, reviewed, templated and generated. It does not make all of those semantics portable to another dashboard.

For migration purposes I would divide Homepage configuration into three layers:

  1. Navigation data: names, URLs and groups. Highly portable.
  2. Presentation data: icons, descriptions, tab membership and layout. Often portable with some loss.
  3. Integration behaviour: service widgets, monitoring and discovery. Usually destination-specific.

That separation is useful when evaluating every other project in this article.

gobookmarks: intentionally small source data

gobookmarks takes almost the opposite approach. Its bookmark data uses a deliberately small text language:

1Tab: Home
2Page: Services
3Column
4Category: Development
5https://github.com GitHub
6https://gitlab.com GitLab
7
8Category: Search
9https://duckduckgo.com DuckDuckGo

The internal hierarchy is essentially:

1Tab
2  Page
3    Block
4      Column
5        Category
6          Entry(URL, Name)

That is a constrained model, but the constraint is part of the design. The file is easy to edit, easy to diff, easy to keep in Git and easy to generate. gobookmarks can use GitHub, GitLab, local Git or SQL-backed providers while retaining the same simple bookmark representation.

The cost is equally clear. A bookmark entry is basically a URL and a name. There is nowhere to preserve arbitrary Homepage fields such as:

1description
2icon
3abbr
4widget
5ping
6highlight

without extending the format.

For Homepage to gobookmarks, the simple case is nearly mechanical:

1- Developer:
2    - GitHub:
3        - href: https://github.com/

becomes:

1Category: Developer
2https://github.com/ GitHub

Homepage tab assignments can map to gobookmarks Tab directives. A Homepage group can map to a category. A service with an href can be reduced to a normal bookmark.

The interesting mismatch is that Homepage can have groups which appear on every tab. gobookmarks structurally owns categories underneath a tab, so an importer would either duplicate those categories into each tab or need a new shared-group concept.

Another mismatch goes in the other direction: gobookmarks has explicit pages within a tab, which do not have a direct Homepage equivalent. A conversion back to Homepage therefore needs to flatten pages or turn them into additional groups or tabs.

The result is asymmetric:

Homepage to gobookmarks is straightforward if the goal is to preserve navigation. gobookmarks to Homepage is also straightforward for links, but a multi-page gobookmarks layout requires a policy decision.

That is still a good migration story because the irreducible data remains very small.

Homer: probably the closest file-based cousin

Homer describes itself as a very simple static homepage and uses a YAML configuration file. That places it close to gobookmarks and the bookmark side of Homepage.

Its configuration describes groups of services and the links inside them, with additional presentation properties. Homer also supports multiple pages and “smart cards” for some richer behaviours.

For a generic migration model, this is a comfortable mapping:

1Homer service group  <-> common group/category
2Homer service item   <-> common link
3Homer page           <-> common page/tab

A Homer item will often contain more display metadata than a gobookmarks entry, but the core is still recognisable as a link in a named group. A converter can preserve the useful minimum and report dropped fields.

This makes Homer one of the easiest applications in the set to treat as configuration data rather than as an opaque application database.

If the main requirement is:

“Give me a static page of organised links, configured in a file and served cheaply”

Homer is much closer to gobookmarks than Homarr or Heimdall are, even though the rendered interfaces may all look like dashboards.

Dashy: YAML with a much larger vocabulary

Dashy also keeps a strong configuration-as-code path. Its main configuration is a YAML file, normally user-data/conf.yml, and the same configuration can also be edited through the user interface.

The useful portable core looks roughly like this:

1sections:
2  - name: Development
3    items:
4      - title: GitHub
5        url: https://github.com/
6        description: Source hosting
7        icon: favicon

Structurally that is an excellent source for conversion:

1section.name  -> category/group
2item.title    -> bookmark name
3item.url      -> bookmark URL

But Dashy’s configuration vocabulary extends much further into theming, search behaviour, status checks, icons, widgets and display rules.

So Dashy has the same broad portability shape as Homepage:

  • links and sections: high
  • descriptions and icons: medium, depending on the destination
  • layout: policy-dependent
  • widgets and status behaviour: low across products

Dashy has an additional practical advantage for migration: the UI and the YAML file are not mutually exclusive worlds. A user can interactively edit the dashboard while still having a textual representation to back up, inspect or transform.

That is an important design point. “Has a UI editor” does not necessarily imply “cannot be configuration as code”.

Glance: a dashboard where bookmarks are one widget

Glance makes the category boundary especially obvious.

Its configuration is YAML, and pages contain columns which contain widgets:

 1pages:
 2  - name: Home
 3    columns:
 4      - size: small
 5        widgets:
 6          - type: calendar
 7
 8      - size: full
 9        widgets:
10          - type: hacker-news
11
12      - size: small
13        widgets:
14          - type: weather
15            location: Melbourne, Australia

Glance also has a bookmarks widget, but bookmarks are one possible component among RSS feeds, videos, weather, calendars, market data, server information, Docker information and other widgets.

This means Glance is technically very portable as configuration: it is declarative YAML and even supports included configuration files. But its semantic centre is different.

Converting a Homepage bookmark group to a Glance bookmarks widget is reasonable.

Converting:

1Homepage service widget -> Glance widget

is not a generic transformation. Sometimes both applications happen to support the same external service; often their widget models, fields and authentication options differ.

Likewise a Glance page containing:

1calendar + RSS + Reddit + weather + markets

cannot meaningfully become a gobookmarks page without throwing away almost everything except links.

So Glance demonstrates why “uses YAML” and “is portable to another YAML dashboard” are not the same statement.

The syntax may be easy to parse while the semantics are incompatible.

Homarr: application state first

Homarr explicitly advertises a different model: no YAML, with drag-and-drop configuration, authentication, user management and a large set of integrations.

For a user who wants to manage a dashboard as an application, that is a feature. The dashboard can have richer user-specific and permission-specific behaviour without forcing users to edit configuration files.

For someone treating the dashboard as repository-managed infrastructure, it changes the migration problem.

The generic link:

1name + URL + icon

is still portable in principle. The surrounding state is application-owned rather than naturally expressed as a small text file.

This creates a useful distinction:

  • semantic portability: another dashboard can represent the same concept;
  • mechanical portability: a deterministic transformer can consume the source configuration directly.

Homarr scores well on semantic portability for ordinary links but lower on mechanical portability than Homepage, Homer, Dashy or gobookmarks.

A migration tool may need an application-specific export, API or database reader before it even reaches a common intermediate model.

Heimdall: mature launcher with enhanced applications

Heimdall is a long-running application dashboard and launcher. At its simplest it is a collection of tiles pointing at applications or arbitrary URLs.

It also has “Enhanced” applications that connect to supported service APIs and display live information.

That makes its conceptual shape familiar:

1plain application tile -> portable link
2enhanced application   -> portable link + non-portable integration

Heimdall itself is an application backed by SQLite rather than a static link configuration file. It does use YAML for configurable search providers, but that YAML is not the primary dashboard data.

As with Homarr, the difficulty is therefore not understanding what a tile means. It is extracting and recreating the state in a supported, reliable way.

A converter from Homepage YAML to Heimdall cannot simply emit another configuration file in the way a Homepage-to-Homer converter could. It would need to target whatever import, API or storage mechanism Heimdall supports.

Flame: simple concepts, database-managed state

Flame sits between the minimal launchers and richer integrated dashboards.

It provides built-in editors for applications and bookmarks, search, authentication, themes, weather and Docker integration. The backend uses SQLite. It also includes an experimental importer for browser HTML bookmarks.

Its conceptual model remains migration-friendly:

1application
2bookmark category
3bookmark

That is much easier to map from gobookmarks or Homepage than a completely widget-driven dashboard would be.

But, again, the source of truth is the key distinction. A SQLite-backed application can represent the same information as a YAML file while still requiring a more specialised import/export path.

Flame’s browser-bookmark importer is an example of the right direction: define a supported boundary between external data and the application’s internal state instead of asking users to mutate the database themselves.

A common denominator exists

Across all of these applications, a surprisingly useful common model can be written down.

Something like:

 1type Dashboard struct {
 2    Pages []Page
 3}
 4
 5type Page struct {
 6    Name   string
 7    Groups []Group
 8}
 9
10type Group struct {
11    Name  string
12    Links []Link
13}
14
15type Link struct {
16    Name        string
17    URL         string
18    Description string
19    Icon        string
20}

is enough to represent the majority of navigation data in every application discussed here.

Tabs and columns can be added:

 1type Dashboard struct {
 2    Tabs []Tab
 3}
 4
 5type Tab struct {
 6    Name  string
 7    Pages []Page
 8}
 9
10type Page struct {
11    Name    string
12    Columns []Column
13}

and application-specific information can be carried in optional metadata:

1type Link struct {
2    Name        string
3    URL         string
4    Description string
5    Icon        string
6    Extra       map[string]any
7}

The important point is that Extra should not be mistaken for interoperability. It is a place to avoid destroying source information during an import/export round trip. A Homepage widget object stored in Extra is still not automatically meaningful to Homer, Dashy or gobookmarks.

A useful migration system therefore needs two levels:

1source format
2    |
3    v
4portable intermediate representation
5    |
6    +--> destination's native concepts
7    |
8    `--> warnings for information that cannot be represented

Warnings are important. Silent loss makes a converter appear more compatible than it really is.

For example:

1Imported 84 links in 11 groups.
2Preserved 4 tabs.
3Dropped 31 descriptions.
4Dropped 47 explicit icons.
5Skipped 12 Homepage service widgets.
6Duplicated 2 global groups across all tabs.

That is a much more honest migration result than claiming “Homepage import supported”.

Pairwise transplantability

For the common case of moving links and their organisation, I would roughly rank the conversions like this:

From / togobookmarksHomepageHomerDashyGlanceHomarr / Heimdall / Flame
gobookmarksNativeHighHighHighMediumMedium
HomepageHighNativeHighHighMediumMedium
HomerHighHighNativeHighMediumMedium
DashyHighHighHighNativeMediumMedium
GlanceMediumMediumMediumMediumNativeLow to medium
DB/UI-managed dashboardsMediumMediumMediumMediumLow to mediumApplication-specific

“High” here means that names, URLs and broad grouping can be transferred without inventing much.

It does not mean the conversion is fully reversible.

The biggest losses tend to be:

  • service-specific widgets;
  • API credentials and field selections;
  • health/status checks;
  • application discovery rules;
  • permissions and users;
  • styling and theme details;
  • responsive layout semantics;
  • application-specific search behaviour;
  • shared/global groups where ownership rules differ.

Why gobookmarks could support importers without changing its format

For gobookmarks specifically, I do not think compatibility argues for replacing its small native format with a Homepage- or Dashy-shaped YAML file.

The small format is the useful part.

Instead, the existing import boundary could grow format-aware converters:

1gobookmarks import native ...
2gobookmarks import homepage ...
3gobookmarks import homer ...
4gobookmarks import dashy ...
5gobookmarks import netscape-html ...

The Homepage importer could accept:

1bookmarks.yaml
2services.yaml
3settings.yaml

and apply explicit rules:

 1Homepage bookmark group
 2    -> gobookmarks Category
 3
 4Homepage bookmark
 5    -> gobookmarks Entry
 6
 7Homepage service with href
 8    -> gobookmarks Entry
 9
10settings.layout.<group>.tab
11    -> gobookmarks Tab
12
13nested Homepage group
14    -> flatten using a documented naming policy
15
16group visible on every Homepage tab
17    -> duplicate into each generated gobookmarks Tab
18
19widget / ping / highlight / icon / description
20    -> warn when not representable

Homer and Dashy importers would be similarly straightforward because their link data already has an obvious textual structure.

For Homarr, Heimdall and Flame, import support would likely start from an exported file, API or documented database migration surface rather than trying to make gobookmarks understand another application’s private storage layout.

This is also a good argument for making importers separate from the storage provider. “Where my gobookmarks file is stored” and “what external format I imported it from” are orthogonal concerns.

Which kind of start page fits which job?

The projects overlap, but their centres of gravity are different.

gobookmarks fits when the bookmark data itself is the important asset: simple text, history, search and a hierarchy that remains easy to understand outside the application.

Homer fits when a static, attractive, YAML-configured launcher is the goal and a server-side application is unnecessary.

Homepage fits when the launcher is also a live operations dashboard, especially around self-hosted services, Docker discovery and service-specific integrations.

Dashy fits when a rich YAML-defined personal dashboard is wanted but interactive editing and a large amount of visual customisation are also valuable.

Glance fits when the page is less a launcher and more an information surface: feeds, calendars, status, media and other widgets, with bookmarks as one component.

Homarr fits when a full application experience, drag-and-drop management, authentication and multiple integrations matter more than keeping the dashboard definition as a small text file.

Heimdall fits the application-launcher model, with a mature catalogue of enhanced applications for users who want more than static tiles.

Flame fits users who want a relatively straightforward apps-and-bookmarks start page with built-in editing and discovery, without making file-based configuration the central workflow.

There is no single winner because “self-hosted homepage” hides at least three separate product categories:

 1bookmark/start-page manager
 2        |
 3        +-- gobookmarks
 4        +-- Homer
 5        `-- Flame
 6
 7service launcher/dashboard
 8        |
 9        +-- Homepage
10        +-- Dashy
11        +-- Heimdall
12        `-- Homarr
13
14information/feed dashboard
15        |
16        `-- Glance

The categories overlap, but they explain why superficially similar screenshots can conceal very different migration characteristics.

The real lock-in test

When evaluating one of these tools, I would now ask four questions before looking at themes or screenshots:

  1. Can I obtain the complete list of links in a documented format?
  2. Can I reproduce the grouping and navigation without clicking through the UI?
  3. Are application-specific integrations cleanly separable from the links they decorate?
  4. Can I version, diff and restore the state using ordinary tools?

A dashboard does not have to answer “yes” to all four. A database-backed multi-user application may reasonably choose different tradeoffs from a static launcher.

But those answers tell you how expensive it will be to change your mind later.

For Homepage, Homer, Dashy and Glance, the configuration is already text and therefore straightforward to inspect and transform. gobookmarks goes further in deliberately keeping its core data model tiny. Homarr, Heimdall and Flame put more state behind the application boundary, which can make the interactive experience better while making generic conversion more application-specific.

The useful conclusion from comparing Homepage and gobookmarks was therefore not that their configurations are compatible. They are not.

It is that the durable core of a start page is much smaller than most dashboard configuration formats:

1name
2URL
3group
4order
5optional page/tab

Everything above that core should be treated as an enhancement with an explicit migration policy.

That is enough common ground to make importers practical, and perhaps enough to justify a small shared interchange model between self-hosted start-page projects without forcing any of them to adopt the same native configuration format.

References