[[configuration-service]]
== Configuration service
{kib} provides `ConfigService` for plugin developers that want to support
adjustable runtime behavior for their plugins.
Plugins can only read their own configuration values, it is not possible to access the configuration values from {kib} Core or other plugins directly.

NOTE: The Configuration service is only available server side.

[source,js]
----
// in Legacy platform
const basePath = config.get('server.basePath');
// in Kibana Platform 'basePath' belongs to the http service
const basePath = core.http.basePath.get(request);
----

To have access to your plugin config, you _should_:

* Declare plugin-specific `configPath` (will fallback to plugin `id`
if not specified) in {kib-repo}blob/{branch}/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md[`kibana.json`] manifest file.
* Export schema validation for the config from plugin's main file. Schema is
mandatory. If a plugin reads from the config without schema declaration,
`ConfigService` will throw an error.

*my_plugin/server/index.ts*
[source,typescript]
----
import { schema, TypeOf } from '@kbn/config-schema';
export const plugin = …
export const config = {
  schema: schema.object(…),
};
export type MyPluginConfigType = TypeOf<typeof config.schema>;
----

* Read config value exposed via `PluginInitializerContext`:

*my_plugin/server/index.ts*
[source,typescript]
----
import type { PluginInitializerContext } from '@kbn/core/server';
export class MyPlugin {
  constructor(initializerContext: PluginInitializerContext) {
    this.config$ = initializerContext.config.create<MyPluginConfigType>();
    // or if config is optional:
    this.config$ = initializerContext.config.createIfExists<MyPluginConfigType>();
  }
  ...
}
----

If your plugin also has a client-side part, you can also expose
configuration properties to it using the configuration `exposeToBrowser`
allow-list property.

*my_plugin/server/index.ts*
[source,typescript]
----
import { schema, TypeOf } from '@kbn/config-schema';
import type { PluginConfigDescriptor } from '@kbn/core/server';

const configSchema = schema.object({
  secret: schema.string({ defaultValue: 'Only on server' }),
  uiProp: schema.string({ defaultValue: 'Accessible from client' }),
});

type ConfigType = TypeOf<typeof configSchema>;

export const config: PluginConfigDescriptor<ConfigType> = {
  exposeToBrowser: {
    uiProp: true,
  },
  schema: configSchema,
};
----

Configuration containing only the exposed properties will be then
available on the client-side using the plugin's `initializerContext`:

*my_plugin/public/index.ts*
[source,typescript]
----
interface ClientConfigType {
  uiProp: string;
}

export class MyPlugin implements Plugin<PluginSetup, PluginStart> {
  constructor(private readonly initializerContext: PluginInitializerContext) {}

  public async setup(core: CoreSetup, deps: {}) {
    const config = this.initializerContext.config.get<ClientConfigType>();
  }
----

All plugins are considered enabled by default. If you want to disable
your plugin, you could declare the `enabled` flag in the plugin
config. This is a special {kib} Platform key. {kib} reads its
value and won’t create a plugin instance if `enabled: false`.

[source,js]
----
export const config = {
  schema: schema.object({ enabled: schema.boolean({ defaultValue: false }) }),
};
----
[[handle-plugin-configuration-deprecations]]
=== Handle plugin configuration deprecations
If your plugin has deprecated configuration keys, you can describe them using
the `deprecations` config descriptor field.
Deprecations are managed on a per-plugin basis, meaning you don’t need to specify
the whole property path, but use the relative path from your plugin’s
configuration root.

*my_plugin/server/index.ts*
[source,typescript]
----
import { schema, TypeOf } from '@kbn/config-schema';
import type { PluginConfigDescriptor } from '@kbn/core/server';

const configSchema = schema.object({
  newProperty: schema.string({ defaultValue: 'Some string' }),
});

type ConfigType = TypeOf<typeof configSchema>;

export const config: PluginConfigDescriptor<ConfigType> = {
  schema: configSchema,
  deprecations: ({ rename, unused }) => [
    rename('oldProperty', 'newProperty'),
    unused('someUnusedProperty'),
  ],
};
----

In some cases, accessing the whole configuration for deprecations is
necessary. For these edge cases, `renameFromRoot` and `unusedFromRoot`
are also accessible when declaring deprecations.

*my_plugin/server/index.ts*
[source,typescript]
----
export const config: PluginConfigDescriptor<ConfigType> = {
  schema: configSchema,
  deprecations: ({ renameFromRoot, unusedFromRoot }) => [
    renameFromRoot('oldplugin.property', 'myplugin.property'),
    unusedFromRoot('oldplugin.deprecated'),
  ],
};
----
[[validating-your-configuration-based-on-context-references]]
=== Validating your configuration based on context references
Some features require special configuration when running in different modes (dev/prod/dist, or even serverless). For purpose, core injects the following _references_ in the validation's context:

[cols="^1,^1,3"]
|===
|Context Reference |Potential values |Description

|`dev`
|`true`\|`false`
|Is Kibana running in Dev mode?

|`prod`
|`true`\|`false`
|Is Kibana running in Production mode (running from binary)?

|`dist`
|`true`\|`false`
|Is Kibana running from a distributable build (not running from source)?

|`serverless`
|`true`\|`false`
|Is Kibana running in Serverless offering?

|`version`
|`8.9.0`
|The current version of Kibana

|`buildNum`
|`12345`
|The build number

|`branch`
|`main`
|The current branch running

|`buildSha`
|`12345`
|The build SHA (typically refers to the last commit's SHA)

|===

To use any of the references listed above in a config validation schema, they can be accessed via `schema.contextRef('{CONTEXT_REFERENCE}')`:

[source,js]
----
export const config = {
  schema: schema.object({
    // Enabled by default in Dev mode
    enabled: schema.boolean({ defaultValue: schema.contextRef('dev') }),

    // Setting only allowed in the Serverless offering
    plansForWorldPeace: schema.conditional(
      schema.contextRef('serverless'),
      true,
      schema.string({ defaultValue: 'Free hugs' }),
      schema.never()
    ),
  }),
};
----
