Skip to content
DMNO
✨ If you've tried DMNO or looked through the docs, let us know what you think!

Plugins

DMNO’s extensible plugin system allows you to add new functionality to your DMNO configuration. Plugins can be used to add new features, add reusable types, integrate with third-party services, or generally extend the core functionality of DMNO.

Available plugins

Our first set of plugins are designed to help you manage secrets:

General plugin guidelines

Plugin inputs

In general, plugins are initialized with a set of inputs that are used to configure the plugin. These inputs usually live in the schema of the DMNO service where the plugin is initialized. While the exact inputs will vary by plugin, they will often include some combination of:

  • Sensitive values that are needed to access the plugin’s service
  • Non-sensitive values that are needed to configure the plugin

Because plugins are typically used to access sensitive items themselves, this introduces a slight chicken-and-egg problem. In this case, DMNO allows you to define the plugin inputs in the schema but not provide a value. The sensitive value is then set via an override.

Wiring up the inputs

Because DMNO provides plugin-specific types, we can automatically inject the correct type for the plugin input. This means you don’t need to manually wire up the inputs when you initialize the plugin. Our config engine will do this for you.

For example:

import { SomePlugin, SomePluginTypes } from '@dmno/some-plugin';
// by default, access token will be injected using types
const somePluginInstance = new SomePlugin('some-plugin');
// or you can explicitly wire it up by path
const somePluginInstance2 = new SomePlugin('some-plugin', {
someToken: configPath('..', 'SOME_TOKEN'),
someOtherToken: configPath('..', 'SOME_OTHER_TOKEN'),
});
export default defineDmnoService({
schema: {
SOME_TOKEN: {
// this type allows us to inject the correct value from the config item
extends: SomePluginTypes.someToken,
},
SOME_OTHER_TOKEN: {
extends: SomePluginTypes.someOtherToken,
},
},
});

Multiple plugin instances

Plugins support multiple instances allowing you to compose your configuration in a flexible way. For example, with the 1Password plugin you could create separate instances for your production and non-production vaults. Each instance can have its own settings, allowing you to manage per-environment or per-service secrets.

When defining a plugin instance, you provide an id which will be used to identify the instance in various places, such as the CLI, UI, and when injecting it into other services.

Injecting plugin instances in monorepo services

In a monorepo, you might want to use the same plugin instance across multiple services. If you will be using the same settings for each service, you can initialize a plugin instance once in a parent service as seen above, and then inject it in child services. This alleviates the need to have the necessary config in each additional service. Note that the injected plugin instance must use the same id we set during initialization.

apps/some-service/.dmno/config.mts
import { SomePlugin } from '@dmno/some-plugin';
// 💉 inject the already initialized plugin instead of re-initializing it
const someInjectedPluginInstance = SomePlugin.injectInstance('some-plugin');

Caching

In order to avoid rate limits and keep dev server restarts extremely fast, we heavily cache data fetched from external sources. After updating secrets from any plugin that stores them externally, if the item has been cached, you’ll need to clear the cache to see it take effect.

  • Use the dmno clear-cache command to clear the cache once
  • The dmno resolve and dmno run commands have cache related flags:
    • --skip-cache - skips caching logic altogether
    • --clear-cache - clears the cache once before continuing as normal