Plugin Config Field Reference
PicGo's Uploader / Transformer / Plugin modules can each expose a set of fields via the config(ctx) method. On the CLI side this array is passed to inquirer.js to render command-line prompts; on the GUI side it is rendered as a visual form.
A minimal example
Here is a simplified GitLab-style Uploader configuration covering a few common field types:
const uploaderConfig = ctx => {
// Read the previously stored config to seed the form with current values
const userConfig = ctx.getConfig('picBed.gitlab') || {}
return [
{
name: 'host', // field name; becomes the key in the final config
type: 'input', // single-line text
alias: 'Host', // field title shown in the GUI form
default: userConfig.host || 'https://gitlab.com',
required: true
},
{
name: 'token',
type: 'password', // masked input
alias: 'Token',
default: userConfig.token || '',
required: true
},
{
name: 'visibility',
type: 'list', // single-select dropdown
alias: 'Visibility',
choices: ['public', 'private'],
default: 'private',
required: false
}
]
}Once your fields are defined, expose them to PicGo according to the dimension:
const handle = ctx => ctx
const uploaderConfig = ctx => [ /* Uploader fields, see above */ ]
const transformerConfig = ctx => [ /* Transformer fields */ ]
const pluginConfig = ctx => [ /* Plugin's own fields */ ]
module.exports = ctx => {
const register = () => {
// The Uploader's config goes with its handle into helper.uploader
ctx.helper.uploader.register('gitlab', {
handle,
config: uploaderConfig
})
// Same pattern for the Transformer
ctx.helper.transformer.register('gitlab', {
handle,
config: transformerConfig
})
}
return {
register,
uploader: 'gitlab', // expose the Uploader name to PicGo so it can be picked
transformer: 'gitlab', // same for the Transformer
config: pluginConfig // the Plugin's own config attaches directly on the exported object
}
}All three dimensions return a field array with identical shape. They only differ in where they're attached and which key in the PicGo config file the values end up under (see The config method).
Tip
ctx.getConfig('picBed.<name>') is the standard "read existing config to seed the form" pattern. Uploader configs live under picBed.<name>, Transformer configs under transformer.<name>, and a Plugin's own config under <pluginFullName> (see The config method for details).
For a real-world Uploader reference, see PicGo-Core's built-in tcyun.ts.
Common fields
All field types support these properties:
| Field | Type | Notes |
|---|---|---|
name | string | Required. The field name; becomes the key in the stored config object |
type | 'input' | 'password' | 'list' | 'checkbox' | 'confirm' | 'editor' | Required. Determines how the field is rendered |
required | boolean | Whether the field is required. GUI adds a red asterisk; CLI blocks empty submissions |
default | unknown | ((answers) => unknown) | Default value. Can be a function — see Reactive fields |
alias | string | Field title in the GUI form. Ignored by the CLI. If omitted, GUI falls back to name |
message | string | CLI prompt text / GUI input placeholder |
tips | string | Help text shown via a ❓ tooltip next to the GUI field title. Supports Markdown (sanitized). Ignored by the CLI |
Tip
alias and tips are PicGo extensions; inquirer doesn't know about them, so the CLI ignores them.
Field types
input — single-line text
A plain string input.
{
name: 'bucket',
type: 'input',
alias: 'Bucket',
default: '',
required: true
}password — masked input
Same as input but the GUI masks the value by default (with a toggle button), and the CLI inquirer hides keystrokes.
{
name: 'secretKey',
type: 'password',
alias: 'SecretKey',
default: '',
required: true
}list — single-select dropdown
Pick one from a set of options. choices is required.
{
name: 'region',
type: 'list',
alias: 'Region',
choices: ['us', 'eu', 'asia'],
default: 'us',
required: true
}choices can be a plain string array (label and value are the same) or an array of objects:
choices: [
{ name: 'North America', value: 'us' }, // GUI shows "North America", stored value is 'us'
{ name: 'Europe', value: 'eu' },
{ name: 'Asia', value: 'asia' }
]checkbox — multi-select
Multi-select list. default is usually an array.
{
name: 'options',
type: 'checkbox',
alias: 'Processing options',
choices: [
{ name: 'Slim', value: 'slim', checked: true }, // checked means initially selected
{ name: 'Watermark', value: 'watermark' }
],
default: ['slim']
}checked only applies to checkbox fields and pre-selects the option on first render.
confirm — yes / no switch
A boolean, rendered as a Switch in the GUI.
{
name: 'slim',
type: 'confirm',
alias: 'Image compression',
confirmText: 'On', // label when toggled to true
cancelText: 'Off', // label when toggled to false
tips: 'Compress images before upload',
default: false
}confirmText / cancelText only apply to confirm fields.
editor — multi-line text 3.0.0+
Use this for fields where users need to enter multi-line text — for example, an API key list, a custom transform/compression script, a template snippet. The stored value is still a string and may contain \n; picgo does no further trimming or processing.
{
name: 'script',
type: 'editor',
alias: 'Compression script',
required: true,
message: 'Enter the compression script (multi-line)'
}Behavior on both sides:
- CLI: inquirer 6's native
editortype opens an external editor with the priorityVISUAL→EDITOR→ platform default (vi/nanoon Unix,notepadon Windows). Whatever the user saves on exit is submitted verbatim; picgo-core doesn't trim or transform it. - GUI: rendered as
<Textarea>that auto-grows with content; users can drag the bottom-right handle to resize manually.
Tip
On Windows, if the default notepad experience isn't great, set EDITOR=code -w (or similar) for a wait-mode editor (the -w flag is required so the CLI blocks until the GUI editor closes). This is inherent inquirer / external-editor behavior; PicGo doesn't intervene.
Reactive fields 3.0.0+
If you want a field's choices or default to react to the current value of other fields — for example, "pick a region first, then derive the bucket list" — you can write choices or default as functions and declare the dependency with dependsOn.
choices and default both support two forms:
- Static value: same as before
- Function:
(answers) => ..., whereanswersis a snapshot of currently known field values (Record<string, unknown>)
dependsOn is an array of field names that this field's evaluation depends on. It's primarily used by the GUI — the GUI watches the listed fields and triggers a refresh whenever any of them changes. On the CLI side, inquirer naturally accumulates answers in prompt order, so dependsOn is just metadata in CLI; it doesn't affect evaluation.
A minimal two-level cascade (region → bucket):
const config = ctx => [
{
name: 'region',
type: 'list',
alias: 'Region',
choices: ['us', 'eu', 'asia'],
default: 'us',
required: true
},
{
name: 'bucket',
type: 'list',
alias: 'Bucket',
dependsOn: ['region'],
// After the user picks a region, this receives the latest answers.region
choices: (answers) => {
if (answers.region === 'eu') {
return ['eu-west-prod', 'eu-central-prod']
}
if (answers.region === 'asia') {
return ['asia-sg-prod', 'asia-tk-prod']
}
return ['us-east-prod', 'us-west-prod']
},
required: true
}
]Tip
Your function must handle answers === {} — when the schema is first serialized (so the GUI can render the initial form), answers is empty. Provide a reasonable fallback for upstream fields, like the example above defaulting to the us branch when answers.region isn't set.
You can use functional choices / default without dependsOn — the CLI still works (inquirer evaluates the functions itself). But the GUI won't know when to refresh, so the dropdown will only show what was computed on first load.
For GUI-side form value merging and refresh behavior, see GUI Plugin Development – Reactive fields.
Error handling
Field-level isolation is the consistent strategy — when one field's function throws, other fields keep working:
choicesfunction throws → that field'schoicesfalls back to[](empty GUI dropdown, no CLI options)defaultfunction throws → that field'sdefaultfalls back toundefined- Both cases log the field name and error via
ctx.log.warn
So you don't need defensive try/catch around your functional choices / default — PicGo has you covered. That said, you should still handle exceptions yourself when you can.
Storage paths
See the JSON example in The config method. In short:
- Uploader:
picBed.<uploaderName>.<fieldName> - Transformer:
transformer.<transformerName>.<fieldName> - Plugin (its own config):
<pluginFullName>.<fieldName>, at the root of the config file
The GUI filters out orphan keys (fields not in the current schema) at save time, so temporary fields produced during cascading don't leak into the persisted config.
