Skip to main content

Add-on Package Structure

An NVDA add-on is distributed as a .nvda-addon file, which is a ZIP archive containing:
myAddon/
├── manifest.ini          # Required: Add-on metadata
├── appModules/           # Optional: Application modules
│   └── myapp.py
├── globalPlugins/        # Optional: Global plugins
│   └── myplugin.py
├── synthDrivers/         # Optional: Speech synthesizers
├── brailleDisplayDrivers/ # Optional: Braille drivers
├── locale/               # Optional: Translations
│   ├── en/
│   │   ├── LC_MESSAGES/
│   │   │   └── nvda.mo
│   │   └── manifest.ini  # Translated manifest
│   └── es/
├── doc/                  # Optional: Documentation
│   ├── en/
│   │   └── readme.html
│   └── es/
└── installTasks.py       # Optional: Install/uninstall tasks

Manifest File

The manifest.ini file contains required metadata:
name = myAddon
summary = My NVDA Add-on
description = A longer description of what this add-on does.
author = Your Name <[email protected]>
version = 1.0.0
minimumNVDAVersion = 2023.1.0
lastTestedNVDAVersion = 2024.1.0
url = https://github.com/yourusername/myaddon
docFileName = readme.html

Manifest Fields

name
str
required
Unique identifier (lowerCamelCase recommended). Used as the add-on ID.
summary
str
required
Short label shown to users (one line).
description
str
Longer description with more details.
author
str
required
Author name and optionally email.
version
str
required
Version number (semantic versioning recommended: major.minor.patch).
minimumNVDAVersion
str
required
Minimum NVDA version required (e.g., 2023.1.0).
lastTestedNVDAVersion
str
required
Last NVDA version tested with this add-on (e.g., 2024.1.0). Must be >= minimumNVDAVersion.
url
str
Homepage or documentation URL (should begin with https://).
docFileName
str
Default documentation filename in doc/ directory.
changelog
str
Version history and changes.

Version Compatibility

API Version Requirements:
  • Set minimumNVDAVersion to the oldest NVDA version you support
  • Set lastTestedNVDAVersion to the latest version you’ve tested
  • Test your add-on with both the minimum and latest versions
  • Update lastTestedNVDAVersion when testing with new NVDA releases
Checking Versions
import addonAPIVersion

# Current NVDA API version
current = addonAPIVersion.CURRENT  # (2024, 1, 0)

# Backwards compatible to
backCompat = addonAPIVersion.BACK_COMPAT_TO  # (2023, 1, 0)

# Check if add-on is compatible
from addonHandler.addonVersionCheck import isAddonCompatible
if isAddonCompatible(addon):
    # Add-on can run
    pass

Install Tasks

Optional installTasks.py module for installation/uninstallation logic:
# installTasks.py - runs during install/uninstall

import addonHandler
import gui
import wx

def onInstall():
	"""Called when add-on is being installed."""
	# Import addon for translations
	addon = addonHandler.getCodeAddon()
	translations = addon.getTranslationsInstance()
	_ = translations.gettext
	
	# Show welcome message
	gui.messageBox(
		_("Thank you for installing My Add-on!"),
		_("Installation Complete"),
		wx.OK | wx.ICON_INFORMATION
	)
	
	# Create config if needed
	import config
	if "myAddon" not in config.conf:
		config.conf["myAddon"] = {}
		config.conf["myAddon"]["enabled"] = True
		config.conf.save()

def onUninstall():
	"""Called when add-on is being uninstalled."""
	# Clean up configuration
	import config
	if "myAddon" in config.conf:
		del config.conf["myAddon"]
		config.conf.save()
	
	# Show farewell
	addon = addonHandler.getCodeAddon()
	translations = addon.getTranslationsInstance()
	_ = translations.gettext
	
	gui.messageBox(
		_("My Add-on has been removed. Thank you for using it!"),
		_("Uninstallation Complete"),
		wx.OK | wx.ICON_INFORMATION
	)
Install tasks have access to the add-on’s translations via addon.getTranslationsInstance().

Translations

Support multiple languages:
1

Create POT file

Extract translatable strings to a template:
xgettext --language=Python --output=myAddon.pot **/*.py
2

Create PO files

Create language-specific files:
msginit --input=myAddon.pot --locale=es --output=locale/es/LC_MESSAGES/nvda.po
3

Translate strings

Edit .po files with translations.
4

Compile to MO

msgfmt locale/es/LC_MESSAGES/nvda.po -o locale/es/LC_MESSAGES/nvda.mo
5

Translate manifest (optional)

Create locale/es/manifest.ini with translated summary, description, and changelog.

Using Translations in Code

translations.py
import addonHandler

# Initialize translations (at top of module)
addonHandler.initTranslation()

# Use translation functions
def myFunction():
	# Simple translation
	message = _("Hello, world!")
	
	# Plural forms
	count = 5
	message = ngettext(
		"{count} item",
		"{count} items",
		count
	).format(count=count)
	
	# Context (disambiguate same English, different meanings)
	message = pgettext("verb", "Open")
	message = pgettext("adjective", "Open")

Documentation

Provide user documentation:
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>My NVDA Add-on</title>
</head>
<body>
	<h1>My NVDA Add-on</h1>
	
	<h2>Description</h2>
	<p>This add-on provides...</p>
	
	<h2>Features</h2>
	<ul>
		<li>Feature 1</li>
		<li>Feature 2</li>
	</ul>
	
	<h2>Keyboard Commands</h2>
	<table>
		<tr>
			<th>Command</th>
			<th>Description</th>
		</tr>
		<tr>
			<td>NVDA+Shift+M</td>
			<td>Opens main dialog</td>
		</tr>
	</table>
	
	<h2>Configuration</h2>
	<p>Settings can be found in NVDA Settings dialog...</p>
	
	<h2>Support</h2>
	<p>For issues, visit: <a href="https://github.com/user/addon/issues">GitHub Issues</a></p>
</body>
</html>

Creating the Package

Manual Packaging

1

Prepare directory

Create directory with all required files in proper structure.
2

Create ZIP archive

cd myAddon
zip -r ../myAddon-1.0.0.nvda-addon *
Or use Python:
from addonHandler import createAddonBundleFromPath
bundle = createAddonBundleFromPath("path/to/myAddon")
3

Rename to .nvda-addon

Ensure file extension is .nvda-addon.

Using Add-on Template

The NVDA Add-on Template provides automated packaging:
# Clone template
git clone https://github.com/nvaccess/AddonTemplate.git myAddon
cd myAddon

# Install dependencies
pip install -r requirements.txt

# Edit manifest and add your code

# Build add-on
scons

# Output: myAddon-1.0.0.nvda-addon

Testing Before Distribution

1

Test installation

Install the packaged add-on and verify it loads correctly.
2

Test in multiple NVDA versions

Test with your minimum and maximum supported versions.
3

Test uninstallation

Ensure clean uninstall with no leftover files or settings.
4

Test upgrades

Install old version, then upgrade to new version.
5

Test translations

Switch NVDA language and verify translations work.
6

Review logs

Check NVDA log for errors or warnings.

Submitting to Add-on Store

The official NVDA Add-on Store is the recommended distribution method:
1

Review submission requirements

2

Create GitHub repository

Host your add-on source on GitHub with proper documentation.
3

Submit via pull request

4

Respond to review

Address any feedback from reviewers.
5

Updates

Submit new versions via pull request with updated manifest.

Store Requirements

Submission Requirements:
  • Source code must be publicly available
  • Add-on must pass automated tests
  • Must follow NVDA coding standards
  • Documentation must be included
  • License must be compatible (GPL preferred)

Alternative Distribution

Besides the Add-on Store, you can distribute via:

Direct Download

  • Host .nvda-addon file on your website
  • Users download and install manually
  • Include clear installation instructions

GitHub Releases

# Create release
git tag v1.0.0
git push origin v1.0.0

# Upload .nvda-addon file to GitHub release

Community Add-ons

Version Updates

When releasing updates:
1

Update version number

Increment version in manifest.ini:
  • Major (1.0.0 → 2.0.0): Breaking changes
  • Minor (1.0.0 → 1.1.0): New features
  • Patch (1.0.0 → 1.0.1): Bug fixes
2

Update lastTestedNVDAVersion

Test with latest NVDA and update if compatible.
3

Update changelog

Document all changes in manifest.ini or separate changelog.
4

Test thoroughly

Test installation, upgrade, and all functionality.
5

Tag release

Create git tag matching version number.

Best Practices

Development:
  • Use semantic versioning
  • Keep comprehensive changelog
  • Test with multiple NVDA versions
  • Provide clear documentation
  • Respond to user issues promptly
  • Follow NVDA coding standards
Security:
  • Don’t include sensitive data in add-on
  • Validate all user input
  • Use HTTPS for all URLs
  • Don’t execute arbitrary code
  • Be careful with file system operations

Continuous Integration

Automate testing with GitHub Actions:
.github/workflows/build.yml
name: Build Add-on

on: [push, pull_request]

jobs:
  build:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install scons markdown
      
      - name: Build add-on
        run: scons
      
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: addon-package
          path: '*.nvda-addon'

Licensing

Choose an appropriate license:
  • GPL v2 or later (recommended, same as NVDA)
  • MIT License
  • Apache License 2.0
Include COPYING.txt or LICENSE.txt in your add-on.

Resources

Build docs developers (and LLMs) love