Repository Structure

To keep repositories clean and organised, OpenMods reads everything it needs from a single .openmods folder at the root of your repo. One manifest file (openmods.json) describes your gallery, links, FAQ, thumbnail, and install rules.

folder The .openmods Folder

Drop a manifest and any media you reference into .openmods/:

your-repo/
├── .openmods/
│ ├── openmods.json // Manifest: links, media, faq, thumbnail, install
│ └── media/ // (Optional) Gallery assets (png, jpg, mp4, etc.)
├── README.md // Standard GitHub readme (rendered on your mod page)
└── * // Your actual mod source code
bolt

One file, every sync

openmods.json is the source of truth. Every refresh rebuilds your links, FAQ, gallery, and thumbnail from what the file says — dashboard tweaks are overwritten by the next sync, so commit your changes.

data_object openmods.json — full example

Every top-level field is optional. Omit a section and that area of your mod page stays untouched.

{ "schemaVersion": 1, "thumbnail": "cover.png", "add-on-of": 42, "links": [ { "label": "Discord", "icon": "chat", "url": "https://discord.gg/abc" }, { "label": "Website", "url": "https://example.com" } ], "media": [ { "type": "image", "url": "screenshot-1.png", "label": "Boss fight" }, { "type": "image", "url": "screenshot-2.jpg" }, { "type": "video", "url": "https://youtube.com/watch?v=xyz" } ], "faq": [ { "question": "How do I install?", "answer": "Use the OpenMods Manager or extract the zip into your game folder." }, { "question": "Is it multiplayer-safe?", "answer": "Yes — fully compatible." } ], "dependencies": { "1.0.0": [ { "modId": 88, "release": "3.2.1" } ], "2.0.0": [ { "modId": 88, "fromRelease": "4.0.0", "toRelease": "4.5.0" }, { "modId": 142 } ] }, "install": { "path": "BepInEx/plugins", "custom-path": { "src/plugin.dll": "BepInEx/plugins/", "config/": "BepInEx/config/" } } }
edit_note

Forgiving parser

JSON comments (//) and trailing commas are accepted, so you can leave notes for collaborators inline.

link links — sidebar links

A list of external links rendered as a styled sidebar section.

label string · required

Visible button text.

url string · required

Destination URL.

icon string · optional

A Material Symbols name (e.g. chat, language) or an emoji. When omitted, OpenMods picks a sensible default for common labels like Discord / Website / Support / GitHub.

image media & thumbnail — gallery

media is the gallery in display order. thumbnail is your mod's hero image.

url string · required

A filename from .openmods/media/ (e.g. cover.png) or a full https:// URL (e.g. a YouTube link). Filenames are resolved against the media folder by basename.

type "image" | "video" · optional

Inferred from the URL extension when omitted. Use video for YouTube/Vimeo embeds.

label string · optional

Caption / alt text. Parsed but not currently rendered — use it as an organisational note.

Supported images

.png · .jpg · .jpeg · .webp · .gif

Supported videos

.mp4 · .webm

warning

Unresolved files are skipped

If a filename isn't found in .openmods/media/, the entry is dropped from the gallery and a warning is logged. Check spelling and the file extension.

quiz faq — questions & answers

A list of { "question", "answer" } pairs. Renders as an interactive accordion on your mod page.

extension add-on-of — declare your mod as an add-on

Numeric mod id of the parent mod. Your mod will appear in that mod's Add-ons section, and its sidebar will show a chip pointing back at the parent.

tag

Where to find a mod's id

Open the mod's page on OpenMods. The id is the number at the end of the URL, e.g. openmods.net/mod/42"add-on-of": 42.

  • check_circle Omit the field → whatever you set in the dashboard stays. Use it for a soft migration.
  • check_circle Set to a positive number → mod becomes an add-on of that parent.
  • check_circle Set to null → clears any existing parent (the mod becomes standalone).
  • warning Unknown ids or self-references are skipped with a warning — the rest of the manifest still applies.

account_tree dependencies — per-release requirements

An object keyed by your mod's release tag. Each value is the list of required mods for that release, replacing whatever was previously recorded. Releases not listed are left untouched.

modId number · required

Numeric mod id of the required mod (same shape as add-on-of — visible in the URL of the mod's page).

release string · optional

Exact-version pin (shortcut for fromRelease == toRelease). Overrides the from/to fields when set.

fromRelease / toRelease string · optional

Inclusive lower/upper bound on acceptable releases of the required mod. Omit one for an open bound. Omit both for "latest".

Resolves to the same constraint labels you see on the mod page:

  • check_circle No bounds → "latest"
  • check_circle release: "3.0.1" → exact pin: "3.0.1"
  • check_circle fromRelease: "3.0.0""3.0.0+"
  • check_circle toRelease: "3.5.0""≤ 3.5.0"
  • check_circle fromRelease + toRelease"3.0.0 → 3.5.0"
history

Inheritance still applies

A release without explicit requirements inherits from the next older release that has them — same behavior as the dashboard. Use "1.0.0": [] to explicitly clear that release's dependencies.

warning

Strict version matching

Release tags must match exactly (case-insensitive) what GitHub shows. Unknown release keys, missing modIds, and unresolved release/fromRelease/toRelease values are skipped with a warning.

deployed_code install — OpenMods Manager rules

Tells the OpenMods Manager desktop app how to lay your release archive into the player's game folder. Without it, the Manager extracts the archive into the game root.

path string · optional

Base directory where archive contents land, relative to the game install root.

custom-path object · optional

Per-file / per-folder mapping. Keys are paths inside the archive; values are destinations relative to the game root. Trailing slashes mark folder copies.

  • check_circle No install block → archive contents drop into the game root, skipping any bundled .openmods/ folder.
  • check_circle Only path → everything lands under that directory.
  • check_circle Only custom-path → mapped files/folders go to their destinations; the rest drop at the game root.
  • check_circle Both → custom-path wins for entries it covers; the rest fall under path.
info

Ship openmods.json in your release

Include .openmods/openmods.json inside your release archive so the Manager can read the install rules without re-fetching the repo.

Ready to distribute your mods?

Join hundreds of other developers using OpenMods to deliver their creations to players faster.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.