Configuration Fields
How a plugin declares user-editable settings, the input vocabulary, and how saved values reach the plugin process at runtime.
configuration is how a plugin asks the user for values it
can't hardcode: API keys, regional preferences, glob
exclusions, feature flags. The admin UI renders the declared
fields as a form, persists the user's input against the
plugin's row, and passes them into the plugin process through
an environment variable on every start.
Declaring fields
configuration lives at the top level of plugin.json:
"configuration": [
{ "key": "tmdbApiKey", "label": "TMDb API Key", "input": "text", "required": false,
"description": "Personal API key for The Movie Database; uses Aviato's shared key when blank" },
{ "key": "language", "label": "Metadata language", "input": "text", "default": "en-US" },
{ "key": "extractGps", "label": "Extract GPS data", "input": "toggle", "default": true }
]Each entry is a ConfigurationField:
| Field | Type | Notes |
|---|---|---|
key | string | The field name. Must be unique within the array. The user's saved value lands at this key in the runtime config object. |
label | string | Display label in the admin form. |
input | FormFieldInput (optional) | Widget type. See below. Defaults to text. |
required | boolean (optional) | When true, the form refuses to save with the field empty. |
default | unknown (optional) | Initial value when the user has not yet saved the form. |
options | unknown[] (optional) | Choices for select and multi-select. |
min / max | number (optional) | Bounds for number and slider. |
description | string (optional) | Helper text shown below the input. |
Input vocabulary
The same enum drives library plugin form schemas via UI views
and the manifest's configuration block (FormFieldInputSchema,
exported from @aviato/plugin-sdk):
input | Renders as | Saved value type |
|---|---|---|
text | Single-line text | string |
number | Numeric spinner | number |
toggle | Switch | boolean |
select | Single-choice dropdown | one of options[] |
multi-select | Multi-choice dropdown | options[] subset |
string-list | Editable list of free-form strings | string[] |
file-path | Path picker (rendered as text) | string |
color | Color swatch | string (hex) |
slider | Range slider with min/max | number |
A field with options should also set input: 'select' or
'multi-select'. The renderer falls back to a text input
otherwise.
What the user sees
Every plugin's configuration is rendered as a form on its
admin page (/admin/plugins/<id>). Saving the form persists
the values, restarts the plugin process, and surfaces a
"configuration changed" entry in the plugin event log.
For the user-facing copy:
- Keep
labelshort and noun-phrase-shaped: "TMDb API Key", "Metadata language". - Use
descriptionfor the why: when to set it, what happens when it's blank, how to obtain a credential. - Mark fields
requiredonly when the plugin genuinely cannot run without them. Arequiredfield that has a default is a contradiction.
How values reach the plugin
Aviato serializes the saved configuration as JSON and injects
it into the plugin process's environment as
AVIATO_PLUGIN_CONFIG when spawning the process:
env: {
...process.env,
AVIATO_PLUGIN_CONFIG: JSON.stringify(pluginConfig),
}Inside the plugin you parse it once at startup:
function parseJsonConfig (value: string | undefined): Record<string, unknown> {
if (!value) return {}
try { return JSON.parse(value) as Record<string, unknown> } catch { return {} }
}
const config = parseJsonConfig(process.env.AVIATO_PLUGIN_CONFIG)
const tmdbApiKey = (config.tmdbApiKey as string | undefined) ?? DEFAULT_TMDB_API_KEY
const language = (config.language as string) ?? 'en-US'Patterns to follow:
- Read once, at module top. The config never changes during a single plugin process's lifetime; when the user saves new values, Aviato restarts the plugin, which means re-importing your module with the new env var. Don't rebuild the config object on every RPC.
- Treat the parsed value as untrusted. Even though it came from Aviato, a downgrade or a hand-edited DB row could include shapes you don't expect. Use Zod or simple typeof guards.
- Provide sensible defaults. Unset is the common case for
optional fields (
required: falsewith nodefault). Default in the plugin, not in the manifest, when the right value depends on plugin logic. - Treat sensitive values like secrets. Aviato stores them
as plain text in the database today. Don't log them, don't
echo them back in events, and don't return them from
getSchema().
Capability-handler config
Some capability handlers also receive the live config as a
parameter. For example, filesystem.scan(config, ...) is
called with the same JSON object you'd see in
AVIATO_PLUGIN_CONFIG. Prefer the parameter when it's
available, since it lets Aviato (in theory) re-call the method
with a different config without restarting the process. For
all other code paths, the env-var form is canonical.
Validation
ConfigurationFieldSchema is intentionally loose. It does not
validate that default, options, min, and max are
coherent with the chosen input. It's the plugin author's job
to keep them consistent, and Aviato's job to render the form
sensibly when they are not. This loose typing also keeps the
schema forward-compatible: adding new input types to the SDK
doesn't break existing plugins, since the manifest accepts any
string and unrecognized inputs fall through to a text field.
Worked examples
Simple text and toggle
"configuration": [
{ "key": "extractGps", "label": "Extract GPS data", "description": "Read GPS coordinates from EXIF data", "input": "toggle", "default": true },
{ "key": "extractCameraInfo", "label": "Extract camera info", "input": "toggle", "default": true }
]Multi-select language preference
"configuration": [
{
"key": "preferredLanguages",
"label": "Preferred subtitle languages",
"input": "multi-select",
"options": ["en", "ja", "es", "fr", "de"],
"default": ["en"]
}
]Glob exclusions
"configuration": [
{
"key": "excludePatterns",
"label": "Exclude patterns",
"description": "Glob patterns to exclude from scanning",
"input": "string-list"
}
]See also
- Plugin manifest
- UI schemas reuses the same field
vocabulary for per-library forms emitted via the
uiview system. aviato-tmdbandaviato-indexer-photosare reference plugins that parseAVIATO_PLUGIN_CONFIG.