Introduction to System Development


This page provides an overview and tutorial of the basic steps required to create an entire Game System from scratch as a module which can be used for your homebrew games or shared with other players.

As an example of a fairly feature-complete game system implementation - please feel free to examine the D&D5e system which has open source code:

Before you Begin

Game system development in Foundry Virtual Tabletop is both rewarding and challenging. If you are considering this process, we encourage you to consider the following advice:

System File Structure

Each game system is a subdirectory within the {userData}/Data/systems path of your Foundry Virtual Tabletop user data location. When developing a new system, we recommend creating your git repository directly within this location for ease of development and testing. Within this directory there are two required files: system.json and template.json which are each explained below. You are free to use your own naming conventions for subdirectories and files within your game system, but we encourage you to use lower-case hyphen-separated file and folder names as a best practice.

A standard example file structure for a minimal system might look like this:


There are three ways to share a created system with others:

  1. Manual Install: You may package the system directory directly into a .zip file which users can extract within their own systems folder.
  2. Manifest Install: Instead of transacting the .zip file directly, you can host that file in a publicly accessible location and provide users with the URL to the system manifest file, which can automate the installation process.
  3. Foundry Package Browser: You can also configure your system to appear within the in-app system browser which will allow Foundry VTT users to install your system with a single click. This requires the package to be submitted to our website listing.

The System Manifest

Each game system must include a system.json file which provides the system specification. This file is required and must be included at the root level of your system folder. The system folder itself must match the "id" attribute designated within the specification file. For example, if we create a game system with the name mysystem, then we would create the file {userData}/Data/systems/mysystem/system.json.

  "id": "mysystem",
  "title": "Minimal World Building",
  "description": "A human-readable description of your system.",
  "version": "1.0.0",
  "compatibility": {
    "minimum": "10",
    "verified": "11",
    "maximum": "11"
  "authors": [
      "name": "me",
  "scripts": [
  "esmodules": [
  "styles": [
  "packs": [
      "name": "monsters",
      "label": "My Monsters",
      "type": "Actor"
      "name": "items",
      "label": "My Items",
      "type": "Item"
"languages": [
      "lang": "en",
      "name": "English",
      "path": "lang/en.json"
  "socket": false,
  "initiative": "1d20",
  "gridDistance": 10,
  "gridUnits": "ft",
  "primaryTokenAttribute": "",
  "secondaryTokenAttribute": "resources.power",
  "url": "https://your/hosted/system/repo/",
  "background": "systems/mysystem/assets/splash.webp",
  "manifest": "https://your/hosted/system/repo/system.json",
  "download": "https://your/packaged/download/"
Required Manifest Attributes

Choose a unique system identifier. This should be an all lower-case string with no special characters. This name must align with the name of the parent directory within which you create the system.


Provide a human readable title for the game system which is displayed when selecting from available systems in the World creation menu.


This field can contain a more lengthy description of the game system. This text will be used to display help or contact information about your system and is also a good place to include any special licensing or attribution information that you need to distribute.


The system version number can be a number or a string depending on what versioning scheme you prefer to use. You should always increment the system version number if you make changes to the Data Template which is described below. When the system version is changed, the platform will automatically migrate all content to match the new Data Template schema.

Optional Manifest Attributes

the compatibility field is an object key for capturing the sub-fields which defines the limits of your module's compatibility based on Foundry Virtual Tabletop version. It contains the following subfields:

The module will not function for versions earlier than this.
The module has been verified to be compatible up to this version.
The module will not function for newer versions than this.
"compatibility": {
	"minimum": 9,
	"verified": "11"
	"maximum": "11"

An array listing each author as an object that can contain the keys name, email, discord, and url. For example:

"authors": [
      "id": "Atropos",
      "discord": "Atropos",
      "url": ""

A less common way of including Javascript with the increasing adoption of ESModules. This field allows you to define an array of JavaScript file paths which should be included whenever this module is being used. Each listed script path should be relative to the module's root directory. All scripts which exist will be automatically included in the game session and loaded in their listed order.


The preferred method for including Javascript with your project. This field allows you to define an array of JS files which use the newer ES6 modules specification. As with scripts, this should be declared as an array. These files are identified separately in the manifest so they may be correctly loaded as a module rather than a script.


You can designate CSS files which should be included in the game session whenever this System is being used. Each listed stylesheet path should be relative to the system root directory. All stylesheets which exist will be automatically included in the game session and loaded in their listed order. As a best practice, we recommend serving stylesheets out of a subdirectory named styles, but this is not required.


Game systems may come bundled with Compendium packs which add pre-generated content for Actors, Items, or other supported Document types. Compendium packs are defined as objects which have their own internal metadata. For each included compendium. These options are listed below:


The compendium pack name - this should be a unique lower-case string with no special characters.


The compendium pack label - this should be a human readable string label which is displayed in the Compendium sidebar in-game.


Since you are creating compendium content specifically for your system, be sure to reference that the content inside each compendium pack requires the system by providing the system name that you chose.


Each compendium pack must designate a specific Document type that it contains. Valid documents include Actor, Item, JournalEntry, RollTable, Cards, Macro, Playlist, or Scene.


Systems can require other modules, systems, or worlds be installed to allow their use. If a module has been installed with dependencies, but its dependencies are missing, it cannot be enabled. Dependencies within relationships are defined as an array of objects containing the following data:


Dependency entries require the id attribute. If only an id is provided, additional details about the module will be discovered from the Foundry VTT website listing.


The type attribute instructs FVTT that the dependency may be on a different type of package. By default dependencies are assumed to be a module, so if you want to depend on a system or world you should be explicit.


The manifest attribute provides an explicit manifest url to be used for downloading the dependency. If a manifest is not provided, the dependency package must exist in the Foundry website directory.

As above, the compatibility of a dependency can be defined, ensuring that the dependency will not be installed if it does not meet the defined requirements..

Example relationships structure:

"relationships": {
  "systems": [{
    "id": "archmage",
    "type": "system",
    "manifest": "",
    "compatibility": {
      "verified": "1.5.0"
  "requires": [{
    "id": "_chatcommands",
    "type": "module",
    "manifest": "",
    "compatibility": {
      "verified": "1.2.0"

The game system may designate an array of languages specifications that it supports by default. Each element in the languages array is an object which defines the language tag, label, and path to its localization file. The elements of a language object are the following:


The official 2-character language code in lower-case letters, for example "en".


The formal and readable name for the language, for example "English".


Path to a JSON file relative to the system directory where language translation strings are provided.


A system may request for a specialized socket namespace to be provided. If set to true, a socket event will be handled by the server with the name system.${id}, in this example case system.mysystem which transacts a arbitrary data object by broadcasting that data to all connected clients. This allows the system to have a reserved channel for messaging events which are needed to coordinate actions across multiple connected clients.


Not every game system uses the concept of initiative, but this field provides the default dice rolling formula that can be used to determine the turn order of Tokens within the combat tracker.


This field designates the default amount of distance that a single grid space should typically represent under this game system. This value configures the default value used when a new Scene is created, but can always be changed for each Scene independently.


This field designates the standard unit of measure used to describe distances under this game system. This defines the default value used when new a new Scene is created, but can always be changed for each Scene independently.


An attribute path within the system data model that points to an object that contains both a value and max key. The prototype Token for each Actor created in this system will automatically have this resource assigned as it's primary bar. Omit this key or set it to null for no default attribute.


An attribute path within the system data model that points to an object that contains both a value and max key. The prototype Token for each Actor created in this system will automatically have this resource assigned as it's secondary bar. Omit this key or set it to null for no default attribute.


A public URL that links to the repository or documentation pages for the game system. This link will be displayed for users to allow them to find more information about your system.

The path to an image that will be used for the background image of your Game System when in the Gallery and Detail views. For example: systems/mysystem/assets/splash-page.jpg

A stable URL that describes the latest release version of your system manifest file. This URL is used for automatic system installation in the Foundry VTT setup screen. This manifest URL is consulted during the system update check to see whether a new system version is available for download. It is important that this address remain stable, otherwise updates will not be detected.


A public URL that provides a zip archive of your system. The archive at this URL is retrieved during the automated system installation or update process.

You can learn more about the fields supported in a package manifest file on the BasePackage and BaseSystem API documentation pages.

The Data Template

In addition to the System Specification file described above, each game system must include a Data Template file named template.json at the root-level of the system folder. For example, if we create a game system with the name mysystem, then we would create and include the file {userData}/Data/systems/mysystem/template.json.

The data template defines a data model which is used by Actor and Item documents within this game system. Normally, Documents in Foundry Virtual Tabletop have strictly defined data schemas - but the system template.json file allows for game systems to extend that schema to contain additional system-specific data attributes.

You can learn more about Data Models and how they work in our article on System Data Models.

The basic structure of the data template provides top-level objects which define schema for each of the Actor and Item document types. Within a single document block, the following keys are supported:

An array of string sub-types for different varieties of Actor or Item document which may be used. Each document type can have its own different schema.
An object of named data templates which define modular and reusable sets of fields which can be included in the schema for multiple types. Consider defining a named template for sets of attributes which are reused across multiple types of Actor or Item documents.
An object block for each sub-type which defines their unique attributes as well as any included template blocks. For attributes which are unique to a single type - you can declare those attributes directly within this block without the need to define a template.

Fields within the data model may have any of the primitive types of string, number, or boolean, or provide an inner Array or Object structure. The provided value defines both the default value for new documents as well as the data type for the field. here is no limitation on the depth or structure of the template - however we encourage logical grouping of similarly themed attributes within named objects as this tends to help with organization and maintainability.

The following provides an example template.json file which uses these tools to define a system template that includes three Actor types: hero, pawn, and villain - as well as two Item types: weapon, and spell. Note how certain templates like resources are included for each Actor type, while certain actor types have additional attributes which only apply to that type.

Example template.json
"Actor": {
  "types": ["hero", "pawn", "villain"],
  "templates": {
    "background": {
      "biography": "",
      "hairColor": "blue"
    "resources": {
      "health": {
        "min": 0,
        "value": 10,
        "max": 10
      "power": {
        "min": 0,
        "value": 1,
        "max": 3
  "hero": {
    "templates": ["background", "resources"],
    "goodness": {
      "value": 5,
      "max": 10
  "pawn": {
    "templates": ["resources"]
  "villain": {
    "templates": ["background", "resources"],
    "wickedness": {
      "value": 5,
      "max": 100
"Item": {
  "types": ["weapon", "spell"],
  "templates": {
    "rarity": {
      "rarity": "Common",
      "price": 20
  "weapon": {
    "templates": ["rarity"],
    "damage": 5
  "spell": {
    "templates": ["rarity"],
    "cost": 2

Resource Attributes

Specific attributes will be recognized by the game system as a "resource" if (and only if) they contain keys which define a value and a max. In the above example, health, power, and goodness would be detected as eligible resources for hero type characters.

How the Data Model is Applied

When a new Document is created in a game using this system, it will automatically have it's own internal data populated to conform to the schema defined in the system template. For example, when using this system, if we were to execute the following code:

const item = await Item.create({name: "Test Weapon", type: "weapon"});
console.log(item); // The created item data structure

We would observe that the item was created and assigned an ID, and the system field contained within the item matches the expected contents defined by the game system template.

  "_id": "e6c7US1VK2cqejVJ",
  "name": "Test Weapon",
  "permission": {
    "default": 0
  "system": {
    "rarity": "Common",
    "damage": 5
  "flags": {},
  "type": "weapon",
  "img": "icons/svg/sword.svg"

Data Model Migrations

Often, during the course of system development, changes to the template data structure are needed. In such cases, if you increment the version number in your system manifest file any existing Actors or Items will be automatically migrated to the latest template data specification when a World that uses the system is next loaded. During this migration process - any newly added data attributes will be added to existing documents, however old attributes which are no longer required by the template are not removed in case that data needs to be migrated.

To apply additional migration rules, the recommended approach is to provide client side logic which detects whether a migration is necessary and uses the client side API to facilitate additional changes.