Contributing to Connections
Connections are schema-driven. A Connection’s structure, identity, lifecycle, and the forms Meshery renders for it are declared in a connection definition that conforms to the Connection schema (connections.meshery.io/v1beta3) in meshery/schemas. Before contributing, familiarize yourself with that schema and read Contributing to Schemas for the development workflow.
This guide explains how to author a connection definition so that Meshery understands a new kind of Connection and offers it in the Connection Wizard. In most cases, authoring a JSON definition is all you need - no UI or server code.
What is a connection definition?
A connection definition is a first-class Registry entity, authored per Model - exactly like Components and Relationships. It declares everything Meshery needs to register, render, and manage a kind of Connection:
- its identity (
kind,type,subType), - its lifecycle (initial
statusand atransitionMapof allowed state transitions), - the forms the Connection Wizard renders (
connectionSchemaandcredentialSchema), and - its visual identity (
styles).
Connection definitions are packaged in the context of a Model. Be sure you understand how Models are created and packaged first - without a Model to belong to, your connection definition is homeless.
Anatomy of a connection definition
Below is a complete, minimal definition for a hypothetical telemetry backend. It uses the generic wizard flow, which is what most contributions should use.
{ "schemaVersion": "connections.meshery.io/v1beta3", "name": "Grafana", "description": "A Grafana instance that brings its dashboards and panels into Meshery.", "kind": "grafana", "type": "telemetry", "subType": "metrics", "status": "registered", "transitionMap": { "registered": [ { "nextState": "connected", "description": "Connect to the Grafana instance." }, { "nextState": "ignored", "description": "Keep the registration but do not connect." } ], "connected": [ { "nextState": "disconnected", "description": "Disconnect the Grafana connection." }, { "nextState": "deleted", "description": "Remove the Grafana connection completely." } ] }, "connectionSchema": { "type": "object", "title": "Grafana Connection", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri", "title": "Grafana Endpoint", "description": "Base URL of the Grafana instance (e.g. http://grafana.example:3000)." }, "name": { "type": "string", "title": "Connection Name", "description": "Optional friendly name for this Grafana connection." } } }, "credentialSchema": { "type": "object", "title": "Grafana Credential", "properties": { "secret": { "type": "string", "title": "API Key or Basic Auth", "description": "API key, or basic-auth credential formatted as username:password." } } }, "styles": { "svgColor": "<svg ...>...</svg>", "svgWhite": "<svg ...>...</svg>" } }
Identity: kind, type, subType
These three fields identify the Connection and determine how the wizard treats it:
kind- the genre of Connection (e.g.grafana,prometheus,kubernetes). The wizard groups credentials and renders icons bykind.type- a broad classification:platform,telemetry,source,collaboration, and so on.subType- a finer classification:orchestration,metrics,git,registry,chat, and so on.
Together they let the UI target a specific Connection with a custom wizard extension when the generic flow is not enough. For reference, the definitions Meshery ships with:
| Connection | kind | type | subType | initial status |
|---|---|---|---|---|
| Kubernetes | kubernetes | platform | orchestration | discovered |
| Grafana | grafana | telemetry | metrics | registered |
| Prometheus | prometheus | telemetry | metrics | registered |
| Artifact Hub | artifacthub | source | registry | registered |
| GitHub | github | source | git | registered |
Lifecycle: status and transitionMap
status is the state a freshly created Connection starts in. Manually registered Connections typically start at registered; resources that Meshery discovers (like Kubernetes) start at discovered.
transitionMap declares the state machine for the Connection: for each state, the list of states it may move to, each with a human-readable description shown as a confirmation prompt in the UI. Use only the canonical states - discovered, registered, connected, disconnected, ignored, maintenance, deleted, and not found - and keep the transitions consistent with their documented meanings. See States and the Lifecycle of Connections for what each state means and which transitions make sense.
The set of transitions Meshery offers a user for a given Connection comes directly from its definition’s transitionMap. If a transition is not declared, it is not offered. Model the lifecycle deliberately.
Forms: connectionSchema and credentialSchema
Both are JSON Schemas. The Connection Wizard renders them directly with react-jsonschema-form - the same library used for Component forms:
connectionSchemabecomes the Configure Connection step. Mark the fields a Connection cannot exist without (such asurl) asrequired. Anameproperty, if present, is used as the Connection’s display name.credentialSchemabecomes the Associate Credential step. Omit it for a Connection that needs no secret - the wizard then skips the credential step entirely.
Because these schemas live on the definition, the wizard needs no per-kind UI code to render them. Adding a property to the schema adds a field to the form.
Visual identity: styles
styles carries inline SVG markup for the kind’s icon: svgColor (for light backgrounds), svgWhite (for dark backgrounds), and optionally svgComplete. Follow the same icon conventions as Components.
Optional metadata
Two optional metadata keys tune wizard behavior:
metadata.flow- force a wizard flow:generic(the default for every kind except Kubernetes) orkubernetes. You rarely need to set this.metadata.docsURL- a documentation link surfaced for the kind in the wizard. Defaults to the Connections concept page.
Where the definition lives
Place the definition as a JSON file in a connections/ folder inside its Model, alongside that Model’s components/ and relationships/:
models/<model>/<version>/connections/<Name>Connection.json
For example, the shipped definitions live under models/meshery-core/.../connections/ as KubernetesConnection.json, GrafanaConnection.json, PrometheusConnection.json, ArtifactHubConnection.json, and GitHubConnection.json. A Model may include any number of connection definitions. Use these existing files as templates.
How the definition is registered and consumed
Registration. On Model registration, Meshery registers the connection definition into the Registry under its Model and registrant - the same path as Components and Relationships. A Model (carrying a registrant) is required. Definitions can also be managed over the registry API:
Method Endpoint Purpose GET/api/registry/connectionsList connection definitions GET/api/registry/connections/{id}Fetch one definition POST/api/registry/connectionsRegister a definition (needs a Model) PUT/api/registry/connections/{id}Update a definition DELETE/api/registry/connections/{id}Remove a definition Consumption. The Connection Wizard lists every registered definition as a creatable kind and renders its
connectionSchemaandcredentialSchemaas wizard steps. Register your definition and it appears in the wizard automatically - no UI changes required.Lifecycle. Registration drives the default connection state machine, which implements these transitions:
discovered β registered | ignored,registered β connected | ignored,connected β disconnected | deleted, anddisconnected β connected | deleted. Connecting persists the Connection and its credential. No server code is required - add a kind-specific action only when the kind needs a reachability probe before it may advance toconnected(Grafana and Prometheus verify their endpoint; Kubernetes has a bespoke machine altogether). Keep thetransitionMapyou author in step with this machine: it is the copy the UI shows for each transition.Seeding. Most Connections are created by a user through the wizard. A few, though, describe something Meshery itself uses, and Meshery seeds those for itself at boot so they are present out of the box - see System-owned Connections below.
After registering, open the Connection Wizard (Connections β Create Connection) and confirm your kind is listed with its icon, that the Configure and Associate Credential steps render your schemas, and that creating a Connection drives the states you declared in the transitionMap.
System-owned Connections
Meshery generates Models and Components from sources it reaches on its own: it pulls packages from Artifact Hub and reads manifests from GitHub repositories. Those sources are Connections too, and Meshery seeds them for itself during boot-time seed-data initialization so a user finds them already present rather than having to create them by hand.
Seeding runs at the end of model registration (SeedComponents β SeedConnections in server/models/), which is also when every path that rebuilds the registry - server start, database reset, hard reset - picks it up. Because the two reset paths drop every table before rebuilding, they re-migrate the full system-table set from one shared list (models.SystemDatabaseModels, applied via AutoMigrateSystemTables) rather than a hand-maintained subset, so the tables a seeded Connection and the Connections page read from - including environment_connection_mappings - always exist after a reset. It is driven entirely by the registry: the set of Connections seeded is derived from the registered connection definitions, never from a list of kinds written into the server. A definition is seeded when both of the following hold:
- Meshery already sources content through the kind - it holds a registrant Connection of that kind that owns registered Models, the host those Models, and the Components and Relationships beneath them, are registered under. This is what separates Artifact Hub and GitHub from Kubernetes, Grafana and Prometheus: the latter describe resources a user brings, and would be meaningless as empty, endpoint-less rows. Registered Models are required rather than merely any registered entity, because registering a connection definition through
POST /api/registry/connectionscreates a registrant of whatever kind the request body names; requiring Models keeps the rule out of reach of request input. - The kind works anonymously - its
credentialSchemamarks nothing asrequired. A seeded Connection is owned by the system and carries no credential, so a kind that cannot be used without one is never seeded.
A seeded Connection takes its name, type and subType from its definition, which is the authoritative identity for the kind. Three properties are deliberately left alone:
statusis not re-asserted. The definition’sstatusis the state a new Connection starts in; once the Connection exists its state belongs to the state machine, so seeding never undoes a user who connected or ignored it.- A credential you attach is preserved. A kind is only seedable because its
credentialSchemamarks nothing asrequired, which is exactly what makes attaching one optional rather than impossible - an Artifact Hub API key, or a GitHub token that raises your API rate limit. Seeding never clearscredentialId, so a credential you add through the wizard survives every subsequent restart. - A user’s own Connections are never touched. Seeding only ever writes the registrant rows Meshery created itself, so a Connection you created of the same kind is left exactly as you left it.
Seeding is idempotent across restarts, and it never adds a Connection row. It only ever rewrites rows that model registration already created, and it writes one only when that row does not already match its definition, so a restarted server performs no seeding work at all.
The registrant block is hand-authored into every model.json, and the shipped blocks are not uniform - some carry a user_id, some omit it. A registrant’s id is a hash of its content, so those spellings register as separate rows and a kind such as artifacthub can already hold several. Seeding stamps the definition’s identity onto exactly one canonical registrant per kind - it reuses whichever registrant already carries that identity, falling back to the lowest id only when none does yet, so the same row is picked on every boot even as a later models release adds more registrant spellings - and leaves every sibling exactly as registration wrote it. Deduplicating the registrant rows themselves would have to repoint registries.registrant_id and is tracked separately in meshery/meshery#20950.
Authoring a definition does not get your kind seeded, and it should not: a Connection to your Grafana or your cluster is yours to create. Seeding exists only for the sources Meshery itself reads from anonymously.
Advanced: customizing the wizard
The generic flow - choose β configure β credential β review β done, all derived from your schemas - covers most Connections. When a Connection needs bespoke steps (Kubernetes, for example, imports clusters from a kubeconfig and offers a MeshSync deployment-mode step), register a connection extension in the Meshery UI at ui/components/connections/wizard/registry.ts.
An extension matches a Connection by kind (optionally narrowed by type/subType) and may override any step; the most specific match wins, and any step left unset falls back to the generic default:
detailsStep,credentialStep,registerStep,receiptStep- override individual steps. SetcredentialStep: nullto remove the credential step (Kubernetes carries its credential inline as a kubeconfig).postConfigSteps- extra steps appended after registration; these also drive the wizard’s configure mode for an already-registered Connection.
Each step implements a small contract - an id and label, a Component to render, and optional canProceed, onNext, nextLabel, and hidden hooks. Use the existing kubernetesExtension as a worked example, and see Contributing to the Meshery UI for building and testing UI changes.
Reach for a custom extension only when the generic, schema-driven flow genuinely cannot express what your Connection needs. A definition-only contribution is easier to review, ships without a UI release, and stays consistent with every other Connection in the wizard.
Authoring best practices
- Use
camelCasefor property names, matching the rest of Meshery’s schemas. - Keep the
transitionMapconsistent with the documented Connection states; do not invent states. - Mark only genuinely required fields as
requiredinconnectionSchema, and omitcredentialSchemawhen no secret is needed. - Start from a shipped definition rather than from scratch.
- Provide both
svgColorandsvgWhiteicons so the kind renders well on light and dark backgrounds.
Contribute your Connection
Submit a pull request to the Meshery repository adding your connection definition to its Model’s connections/ folder, so every user benefits from the new Connection kind. Follow the contribution gitflow and sign off your commits.
Prefer to keep a Connection definition private? Bundle it in a custom Model and import that Model into your Meshery deployment. Your definition is registered in your Meshery Server’s Registry and offered in your Connection Wizard, without being published upstream.
Discussion Forum
Don't find an answer to your question here? Ask on the Discussion Forum.