Package Metadata
The package.json
file is a JSON file that contains metadata about a JavaScript package. It is a Node.js standard that is expanded upon in the NPM ecosystem, and is required for all packages published to NPM or a similar package registry.
Known Metadata Fields
This section documents the known package.json
metadata fields that play a significant role in the Backstage ecosystem.
All fields defined by NPM are inherited by the Backstage ecosystem. The list below only includes those standard fields for which additional information is available.
name
The name of the package, as defined by NPM. In addition, the following naming scheme is strongly encouraged for packages published in the Backstage ecosystem:
First pick a package name prefix that is unique to your organization or collection of packages, but also places it within the Backstage ecosystem, for example: @example/backstage
, @example-backstage/
, or example-backstage
. This prefix should be used by all packages that you publish, regardless of whether they're part of a plugin or not.
Any package that is not part of a plugin should use the prefix along with a descriptive name, for example: @example/backstage-components
or @example/backstage-foo-client
.
For plugin packages you should also pick a plugin ID and add plugin-<pluginId>
to the prefix, along with a suffix based on the package role:
<prefix>-plugin-<pluginId>
: The main frontend code of the plugin.<prefix>-plugin-<pluginId>-module-<name>
: Optional modules related to the frontend plugin package.<prefix>-plugin-<pluginId>-backend
: The main backend code of the plugin.<prefix>-plugin-<pluginId>-backend-module-<name>
: Optional modules related to the backend plugin package.<prefix>-plugin-<pluginId>-react
: Shared widgets, hooks and similar that both the plugin itself and third-party frontend plugins or modules can depend on.<prefix>-plugin-<pluginId>-node
: Utilities for backends that both the plugin backend itself and third-party backend plugins or modules can depend on.<prefix>-plugin-<pluginId>-common
: An isomorphic package with platform agnostic models, clients, and utilities that all packages above or any third-party plugin or module can depend on.
For example, a frontend package for the poetry
plugin might be called @example/backstage-plugin-poetry
, and a backend package for the same plugin might be called @example/backstage-plugin-poetry-backend
.
If you are creating a module for an existing package that is not part of your project, you should use the same prefix along with the plugin ID of the package that the module is for. For example, if you are creating a poetry provider module for @backstage/plugin-catalog-backend
, you might call it @example/backstage-plugin-catalog-backend-module-poetry-provider
.
repository
The location of the source code for the package, as defined by NPM.
This field can be generated by the backstage-cli repo fix --publish
command. The only requirement is that the package.json
in your workspace root has the repository
field documented.
main
The main entry point of the package, as defined by NPM. In a standard Backstage setup this should point to the entry point for local development, typically src/index.ts
. This field along with other entry point fields such as module
and types
are rewritten when packaging the package for distribution. You can read more about this process in the publishing section, and it is also used for backend production builds.
exports
The exports of the package, as defined by Node.js. This field is used to define the entry points of the package. As with other entry point fields, the exports should point to entry points for local development. They will the be rewritten when packaging the package for distribution. You can read more about this in the sub-path exports section.
typeVersions
This field is used to specify versioned type entry points for the package, as defined by TypeScript, and is used as the equivalent of the exports
field. TypeScript does support type declarations in the exports
field, but that requires that the moduleResolution
option in tsconfig.json
is set to node16
or bundler
, which the Backstage ecosystem currently does not support.
This field can be generated by the backstage-cli repo fix
command. First fill out the exports
field to point to source fields, which will then be used to generate typeVersions
.
sideEffects
This field declares whether it is safe to remove unused code through tree shaking when bundling this package into a frontend build, and is defined for example by WebPack.
This field can be generated by the backstage-cli repo fix
command. It will set to false
by default for all frontend packages, since Backstage frontend packages should generally never have any side effects. If your package does have side effects, you can set explicitly set this field to true
.
scripts
The package scripts as defined by NPM. The Backstage CLI provides a set of standard scripts, which you can read more about in the build system section. The full list of scripts is as follows:
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
}
configSchema
The Backstage configuration schema for the package, as described in the defining configuration section.
backstage
This field is a collection of Backstage specific metadata fields. It is required for all Backstage packages, and any package that defines this field is considered to be part of the Backstage ecosystem. All sub-fields of this collection are defined below.
backstage.role
This field defines the role of the package in the Backstage ecosystem. It can affect both the build process and runtime behavior, and signals the intended usage of the package to consumers. You can read more about this field in the package roles section.
backstage.pluginId
For any package that is part of a plugin, this field should be set to the plugin ID. This is the same ID as you would pass to the createPlugin
, createBackendPlugin
, or createBackendModule
functions in the implementation of the package. It is also the same ID as the one described in the name section.
This field can be generated by the backstage-cli repo fix --publish
command. The plugin ID will be inferred from the package name and role. If the package name is not actually part of a plugin but still has plugin-*
in its name, you can set this field to be explicitly null
.
The presence of this field is checked by the backstage-cli package prepack
command, which is used to prepare a package for publishing. You can read more about this requirement in the section on metadata for published packages.
backstage.pluginPackages
For any package that is part of a plugin, this field should be set to a list of all packages that are directly part of the same plugin. This includes frontend and backend plugin packages as well as related libraries, but not modules.
This field can be generated by the backstage-cli repo fix --publish
command. It will list all packages with the same plugin ID in the workspace.
The presence of this field is checked by the backstage-cli package prepack
command, which is used to prepare a package for publishing. You can read more about this requirement in the section on metadata for published packages.
{
"name": "@backstage/plugin-catalog",
"backstage": {
"role": "frontend-plugin",
"pluginId": "catalog",
"pluginPackages": [
"@backstage/plugin-catalog",
"@backstage/plugin-catalog-backend",
"@backstage/plugin-catalog-common",
"@backstage/plugin-catalog-node",
"@backstage/plugin-catalog-react"
]
}
...
}
backstage.pluginPackage
For any module package of a plugin, this field should be set to the name of the plugin package that this is a module for.
This field can be generated by the backstage-cli repo fix --publish
command. It checks for packages with a matching plugin ID in the same workspace, but also knows the package names of the core feature plugin IDs such as catalog
, auth
, scaffolder
, etc. If the package name can not be inferred, it has to be provided manually.
The presence of this field is checked by the backstage-cli package prepack
command, which is used to prepare a package for publishing. You can read more about this requirement in the section on metadata for published packages.
{
"name": "@backstage/plugin-catalog-backend-module-github",
"backstage": {
"role": "backend-plugin-module",
"pluginId": "catalog",
"pluginPackage": "@backstage/plugin-catalog-backend"
}
...
}
backstage.moved
This field indicates that a package has been renamed and moved to a new location. This field is recognized by the Backstage CLI, where the version bump command will automatically switch to using the new package instead. The value of this field should be the new package name.
{
"name": "@backstage/plugin-azure-devops",
"backstage": {
"moved": "@backstage-community/plugin-azure-devops"
}
...
}
backstage.inline
If set to true
this field indicates that monorepo package is private and should be inlined into dependent packages rather than being treated as a dependency. This effectively means that all imported code from the inlined package will be copied into the consuming package, once for each package.
This flag affects various parts of the Backstage tooling, for example the way the Backstage CLI builds work, the way that @backstage/eslint-plugin
lints dependencies on the package, and how it's treated by @backstage/repo-tools
.
The backstage.inline
field is primarily intended to aid in the implementation of the Backstage core framework in the main Backstage repository, but it can be used in other projects as well.
Setting this flag also requires the top-level private
field to be set as well, since inline packages should not be published.
{
"name": "@internal/utils",
"backstage": {
"inline": true
}
...
}
Metadata for Published Packages
When publishing a package with the help of the Backstage CLI, there are a number of metadata checks that are performed to ensure that the package is correctly set up for the Backstage ecosystem. These checks are performed by the backstage-cli package prepack
command, which is used to prepare a package for publishing. These checks can all also be verified separately using the backstage-cli repo fix --publish
command, and in many cases the required metadata can be generated automatically. It is therefore important to make running the fix
command part of your workflow in any project that is publishing Backstage packages.
To set this up, we recommend that you add the following script to the root package.json
of your workspace:
{
"scripts": {
"fix": "backstage-cli repo fix --publish"
}
}
This allows anyone working in the repo to run yarn fix
to check and update all packages in the workspace.
In addition, you should also add a check to your CI pipeline that ensures that there are no pending fixes. This is done by calling the command with the --check
flag, which in GitHub actions would look something like this:
- name: check for missing repo fixes
run: yarn fix --check
Finally, if you are using Husky or any other pre-commit hook, you can also set up a hook to run the fix command before committing:
{
"lint-staged": {
"package.json": [
"yarn fix"
]
}
}