Reference
Understand every setting in project.json
NovaModuleTools reads project.json to decide how your project is scaffolded, built,
tested, packaged, uploaded, published, and released. Use this page to understand what each setting does,
what the defaults are, and when you should override them.
How to read this file
Think of project.json in layers:
- Top-level project settings control the build shape, source markers, resource copying, and duplicate-function validation.
Manifestcontrols metadata for the generated PowerShell module manifest and package metadata reuse.Packagecontrols package creation and optional raw HTTP upload defaults.Pestercontrols the test run configuration used byInvoke-NovaTestandTest-NovaBuild.
You only need to add settings when you want to override the default workflow. For example, if you
never add a Package section, New-NovaModulePackage still works and
defaults
to a single .nupkg written to artifacts/packages/.
The unified JSON schema covers all documented fields including
Manifest.ReleaseNotes, Manifest.LicenseUri,
Manifest.IconUri, and Pester.TestResult.OutputFormat. VS Code picks
up the schema automatically when the $schema field is present in
project.json.
Complete example
The packaged example project is the best real-world reference because it shows the current full configuration surface in one place.
{
"ProjectName": "NovaExampleModule",
"Description": "A working example project that demonstrates NovaModuleTools.",
"Version": "0.1.0",
"CopyResourcesToModuleRoot": false,
"BuildRecursiveFolders": true,
"SetSourcePath": true,
"FailOnDuplicateFunctionNames": true,
"Preamble": [
"Set-StrictMode -Version Latest",
"$ErrorActionPreference = 'Stop'"
],
"Manifest": {
"Author": "NovaModuleTools",
"PowerShellHostVersion": "7.4",
"GUID": "b3b4ca64-a274-4768-872d-2b3c8bc12a39",
"Tags": ["Example", "NovaModuleTools", "PowerShell"],
"ProjectUri": "https://www.novamoduletools.com/",
"ReleaseNotes": "https://www.novamoduletools.com/release-notes.html",
"LicenseUri": "https://www.novamoduletools.com/license.html"
},
"Package": {
"Id": "NovaExampleModule",
"Types": ["NuGet", "Zip"],
"Latest": "stable",
"OutputDirectory": {
"Path": "artifacts/packages",
"Clean": true
},
"PackageFileName": "NovaExampleModule",
"AddVersionToFileName": true,
"FileNamePattern": "NovaExampleModule*",
"Authors": ["NovaModuleTools", "Example Maintainer"],
"Description": "Example package metadata and raw upload configuration for NovaExampleModule.",
"RepositoryUrl": "https://packages.example.test/raw/novamodule/",
"UploadPath": "stable/latest",
"Headers": {
"X-Client-Id": "nova-example"
},
"Auth": {
"HeaderName": "Authorization",
"Scheme": "Bearer",
"TokenEnvironmentVariable": "NOVA_EXAMPLE_PACKAGE_TOKEN"
},
"Repositories": [
{
"Name": "ExampleRaw",
"Url": "https://packages.example.test/raw/novamodule/"
}
]
},
"Pester": {
"CodeCoverage": {
"Enabled": false,
"Path": [
"src/public/*.ps1",
"src/private/**/*.ps1",
"src/classes/*.ps1"
],
"CoveragePercentTarget": 90,
"OutputPath": "artifacts/coverage.xml",
"OutputFormat": "JaCoCo"
},
"TestResult": {
"Enabled": true,
"OutputFormat": "NUnitXml"
},
"Output": {
"Verbosity": "Detailed"
}
}
}
Top-level project settings
When nova init scaffolds a new project, it injects a $schema field
pointing to the versioned public schema at
https://www.novamoduletools.com/schema/v{major}/project.json, and also writes a
.vscode/settings.json entry that maps project.json to the same URL.
Together these two outputs let VS Code load the schema and provide IntelliSense, field
validation, and hover descriptions without a manual trust prompt. To enable this on an existing
project, add the $schema field as the first key in project.json and
add the matching json.schemas entry to .vscode/settings.json.
| Setting | Purpose | Default | Workflow effect |
|---|---|---|---|
$schema |
Optional URI pointing to the versioned JSON schema for this file. | Injected automatically by nova init |
Enables VS Code IntelliSense, field validation, and hover descriptions while editing
project.json.
|
ProjectName |
Name of the module and the output folder under dist/. |
Required | Determines manifest name, module name, and many generated paths. |
Description |
Human-readable project description. | Required | Feeds manifest and package metadata when you do not override them later. |
Version |
Current semantic version stored for the project. | Required | Used in package names, manifest metadata, % nova version, and release
flows.
|
CopyResourcesToModuleRoot |
Controls where resources are copied in the built module. | false |
When false, resources stay in a resources/ folder. When true,
they are copied into the module root.
|
BuildRecursiveFolders |
Controls recursive discovery for classes, private helpers, and tests. | true |
Affects how nested source files and nested tests are discovered. |
SetSourcePath |
Controls # Source: markers in the generated .psm1. |
true |
Makes parser and runtime errors easier to map back to source files. |
FailOnDuplicateFunctionNames |
Fails the build when duplicate top-level function names are emitted. | true |
Protects the generated module from ambiguous exports and hidden overwrites. |
Preamble |
Optional lines written at the top of the generated .psm1. |
Empty array | Useful for Set-StrictMode, $ErrorActionPreference, or other
module-wide setup lines.
|
Examples
{
"CopyResourcesToModuleRoot": true,
"BuildRecursiveFolders": false,
"SetSourcePath": true,
"FailOnDuplicateFunctionNames": true,
"Preamble": [
"Set-StrictMode -Version Latest",
"$ErrorActionPreference = 'Stop'"
]
}
Use this pattern when you want strict runtime defaults, top-level-only test discovery, and resources copied directly to the module root.
Manifest settings
These settings feed the generated PowerShell module manifest and, in several cases, package metadata.
| Setting | Required | What it does | Notes |
|---|---|---|---|
Author |
Yes | Sets the manifest author and the default package author when
Package.Authors is omitted.
|
Use a single author string; package logic can later expand into arrays. |
PowerShellHostVersion |
Yes | Defines the minimum PowerShell version expected by the generated module. | Users see this in the manifest and module compatibility expectations. |
GUID |
Yes | Sets the manifest GUID. | Generate a new GUID for each distinct module. |
Tags |
No | Adds manifest tags and is reused by package metadata when present. | Optional in practice and safe to omit. |
ProjectUri |
No | Publishes a project URL in the manifest and package metadata. | Explicitly described in the current build schema. |
ReleaseNotes |
No | Publishes a release notes link for packaging and user-facing metadata. | Used by the current product and examples even though the build schema does not enumerate it separately yet. |
LicenseUri |
No | Publishes a license URL for packaging and manifest metadata. | Used in practice and shown in the packaged example. |
IconUri |
No | Publishes an icon URL in the manifest. | Used by the repository project itself and worth keeping stable when you publish publicly. |
If Tags, ProjectUri, ReleaseNotes, or LicenseUri
are omitted, packaging still succeeds. The corresponding package metadata fields are simply left
out.
Package settings
The Package section controls two related but different concerns:
- package creation via
New-NovaModulePackage/% nova package - raw HTTP artifact upload via
Deploy-NovaPackage/% nova deploy
Package.Types, Package.Latest, and OutputDirectory decide
what gets created. RepositoryUrl, Headers, Auth, and
Repositories decide how existing artifacts are uploaded later.
Package creation settings
| Setting | Default | What it controls | Gotchas |
|---|---|---|---|
Id |
ProjectName |
The package identifier and default naming base. | Override this only when the package identity should differ from the module name. |
Types |
["NuGet"] |
Which package formats to create. | Supported values are NuGet, Zip, .nupkg, and
.zip, and matching is case-insensitive.
|
Latest |
"never" |
Controls whether Nova creates companion latest artifacts for each selected type. |
Use "stable" to update latest only for stable versions, "always" for both stable and preview versions, or "never" to disable the floating alias.
|
OutputDirectory.Path |
artifacts/packages |
Where packages are written. | This is also the default discovery location for Deploy-NovaPackage. |
OutputDirectory.Clean |
true |
Whether to clear the output directory before packaging. | Set it to false only when you intentionally want to retain older files.
|
PackageFileName |
<Id>.<Version>.nupkg |
Base file name used for package generation. | Nova normalizes the extension per package type. When you combine a custom base name with
AddVersionToFileName, Nova appends the project version before the extension
and can still swap that suffix for latest when needed.
|
AddVersionToFileName |
false |
Appends .<Version> from the top-level project version to the
configured
PackageFileName.
|
Useful when PackageFileName is a stable base name such as
AgentInstaller. With Latest enabled, Nova substitutes the
appended version suffix with .latest for the companion artifact.
|
FileNamePattern |
<Id>* in practice |
Pattern used to discover matching package files for upload. | When you omit it, Nova falls back to <Id>* and adds the active
package
type extension during discovery. When you set it, your pattern overrides that default.
If PackageFileName uses a different base name than Id, update
FileNamePattern too so deploy discovery still matches the generated files.
A pattern that already ends with .zip or .nupkg is treated as
authoritative, so MyModule.*.zip matches MyModule.1.2.3.zip
and MyModule.latest.zip without discovering .nupkg files.
|
Authors |
Derived from Manifest.Author |
Package author metadata. | Can be a single string or an array of strings. |
Description |
Derived from top-level Description |
Package description metadata. | Use this when the package description should differ from the module description. |
Raw upload settings
| Setting | What it does | Notes |
|---|---|---|
RepositoryUrl |
Canonical package-level raw upload base URL. | Use this when you only need one default upload target. |
RawRepositoryUrl |
Legacy compatibility alias. | If present, it still maps into RepositoryUrl when the canonical setting is
missing.
|
UploadPath |
Optional extra path segment appended before the file name during upload. | Useful for folder-style raw repositories such as stable/latest or preview.
|
Headers |
Generic additional HTTP headers. | Merged with repository-specific headers and dynamic parameter headers when you invoke upload. |
Auth.HeaderName |
Name of the authentication header to emit. | Examples: Authorization, X-Api-Key. |
Auth.Scheme |
Optional scheme prefix for the auth header value. | Examples: Bearer, Basic. |
Auth.Token |
Literal token value. | Good for local testing only. Prefer environment variables for real secrets. |
Auth.TokenEnvironmentVariable |
Name of the environment variable that stores the token value. | This should be the variable name, not the secret itself. |
Repositories |
Named upload targets with optional overrides. | Each repository needs Name and Url, then can add UploadPath,
Headers, and Auth.
|
Nova resolves raw-upload settings in a fixed order so CI/CD overrides stay predictable. Command
arguments such as -Url / --url and -UploadPath /
--upload-path win first, then the selected Package.Repositories[] entry,
then package-level defaults such as Package.RepositoryUrl,
Package.RawRepositoryUrl, and Package.UploadPath.
Secrets follow a matching precedence model. An explicit token value wins first, then an explicit
token-environment-variable name, then the merged repository/package
Auth.TokenEnvironmentVariable, and finally the merged literal
Auth.Token. Prefer environment-variable indirection for real credentials.
Authentication examples
{
"Package": {
"RepositoryUrl": "https://packages.example/raw/",
"Auth": {
"HeaderName": "Authorization",
"Scheme": "Bearer",
"TokenEnvironmentVariable": "NOVA_PACKAGE_TOKEN"
}
}
}
Use this for bearer-token-style endpoints.
{
"Package": {
"Repositories": [
{
"Name": "RawRepo",
"Url": "https://packages.example/raw/",
"Auth": {
"HeaderName": "X-Api-Key",
"TokenEnvironmentVariable": "NOVA_PACKAGE_API_KEY"
}
}
]
}
}
Use this for custom API-key headers.
{
"Package": {
"Repositories": [
{
"Name": "LocalNexus",
"Url": "http://localhost:8081/repository/raw/modules/",
"Auth": {
"HeaderName": "Authorization",
"Scheme": "Basic",
"TokenEnvironmentVariable": "NOVA_NEXUS_BASIC_AUTH"
}
}
]
}
}
Use this generic model for Basic auth when the endpoint expects a pre-encoded token value. In that
case, the environment variable should hold the Base64 value for username:password, not
the raw username or password.
Pester settings
NovaModuleTools passes your Pester settings into the managed test run configuration used by
Invoke-NovaTest and Test-NovaBuild.
| Setting | Current usage | Default/Example | Where you see it |
|---|---|---|---|
Pester.TestResult.Enabled |
Controls whether test results are configured for output. | true in the project template and packaged example |
Influences the generated test result artifact behavior. |
Pester.TestResult.OutputFormat |
Passed through by the current project template and examples. | NUnitXml |
Determines the result format written to the managed NUnit result artifacts. |
Pester.CodeCoverage.Enabled |
Turns the standard Nova coverage pass on or off. | false in the project template and packaged example |
When enabled, the test workflow also writes the configured coverage report and enforces the configured target. |
Pester.CodeCoverage.Path |
Declares which source files the coverage run analyzes. | src/public/*.ps1src/private/*.ps1src/private/*/*.ps1src/private/*/*/*.ps1src/classes/*.ps1
|
These defaults ship in new starter projects so coverage can be enabled without
hand-authoring the file list, including nested helper folders such as
src/private/build/manifest/ and src/private/quality/duplicates/.
|
Pester.CodeCoverage.CoveragePercentTarget |
Sets the minimum coverage percentage the test workflow must meet. | 90 in the project template and packaged example |
Shown in Pester's coverage summary and enforced by Nova when coverage is enabled. |
Pester.CodeCoverage.OutputPath |
Sets where the coverage report is written. | artifacts/coverage.xml |
The JaCoCo report file emitted when coverage is enabled. |
Pester.CodeCoverage.OutputFormat |
Controls the coverage report format. | JaCoCo |
Keeps the coverage artifact ready for tools that expect JaCoCo XML. |
Pester.Output.Verbosity |
Controls Pester console verbosity. | Detailed in the current project template |
Affects what you see during Invoke-NovaTest, Test-NovaBuild, and % nova test.
|
Starter projects now include the full Pester.CodeCoverage block with
the explicit default source globs shown above. The minimal scaffold keeps
Enabled=false, while the packaged example scaffold sets Enabled=true so
coverage works against src/**/*.ps1 immediately. At runtime,
Invoke-NovaTest and Test-NovaBuild both let you override verbosity and render mode temporarily with
-OutputVerbosity and -OutputRenderMode.
When you enable coverage, Nova writes JaCoCo output to artifacts/coverage.xml and fails
the test workflow if the measured percentage is lower than
Pester.CodeCoverage.CoveragePercentTarget.
Common recipes
Minimal module project
{
"ProjectName": "MyModule",
"Description": "My module",
"Version": "0.1.0",
"Manifest": {
"Author": "You",
"PowerShellHostVersion": "7.4",
"GUID": "00000000-0000-0000-0000-000000000000"
}
}
Use this when you want the smallest hand-authored Nova project. Scaffolded projects start with
additional Pester defaults; the minimal scaffold keeps CodeCoverage
disabled until you opt in, while the packaged example scaffold enables it by default. Nova can
still resolve its normal defaults when those sections are omitted.
Create both NuGet and Zip artifacts, plus latest aliases
{
"Package": {
"Types": ["NuGet", "Zip"],
"Latest": "stable",
"OutputDirectory": {
"Path": "artifacts/packages",
"Clean": true
}
}
}
This creates four files for stable versions when both package types are selected: versioned and
latest variants for each format.
Use named raw repositories with shared defaults
{
"Package": {
"RepositoryUrl": "https://packages.example/raw/default/",
"Headers": {
"X-Client": "my-module"
},
"Auth": {
"HeaderName": "Authorization",
"Scheme": "Bearer",
"TokenEnvironmentVariable": "NOVA_PACKAGE_TOKEN"
},
"Repositories": [
{
"Name": "Stable",
"Url": "https://packages.example/raw/stable/"
},
{
"Name": "Preview",
"Url": "https://packages.example/raw/preview/",
"UploadPath": "nightly"
}
]
}
}
Use package-level values for the shared default behavior, then override only the repository-specific
parts that need to change. Repository-specific Headers, Auth, and
UploadPath override package defaults only for the selected named target.