Skip to content

Plugins

The dstack plugin system allows extending dstack server functionality using external Python packages.

Experimental

Plugins are currently an experimental feature. Backward compatibility is not guaranteed across releases.

Enable plugins

To enable a plugin, list it under plugins in server/config.yml:

plugins:
  - my_dstack_plugin
  - some_other_plugin
projects:
- name: main

On the next server restart, you should see a log message indicating that the plugin is loaded.

Create plugins

To create a plugin, create a Python package that implements a subclass of dstack.plugins.Plugin and exports this subclass as a "dstack.plugins" entry point.

  1. Init the plugin package:

    $ uv init --library
    
  2. Define ApplyPolicy and Plugin subclasses:

    from dstack.plugins import ApplyPolicy, Plugin, RunSpec, get_plugin_logger
    
    logger = get_plugin_logger(__name__)
    
    class ExamplePolicy(ApplyPolicy):
        def on_run_apply(self, user: str, project: str, spec: RunSpec) -> RunSpec:
            # ...
            return spec
    
    class ExamplePlugin(Plugin):
    
        def get_apply_policies(self) -> list[ApplyPolicy]:
            return [ExamplePolicy()]
    
  3. Specify a "dstack.plugins" entry point in pyproject.toml:

    [project.entry-points."dstack.plugins"]
    example_plugin = "example_plugin:ExamplePlugin"
    

Then you can install the plugin package into your Python environment and enable it via server/config.yml.

Plugins in Docker

If you deploy dstack using a Docker image you can add plugins either by including them in your custom image built upon the dstack server image, or by mounting installed plugins as volumes.

Apply policies

Currently the only plugin functionality is apply policies. Apply policies allow modifying specs of runs, fleets, volumes, and gateways submitted on dstack apply. Subclass dstack.plugins.ApplyPolicy to implement them.

Here's an example of how to enforce certain rules using apply policies:

class ExamplePolicy(ApplyPolicy):
    def on_run_apply(self, user: str, project: str, spec: RunSpec) -> RunSpec:
        # Forcing some limits
        spec.configuration.max_price = 2.0
        spec.configuration.max_duration = "1d"
        # Setting some extra tags
        if spec.configuration.tags is None:
            spec.configuration.tags = {}
        spec.configuration.tags |= {
            "team": "my_team",
        }
        # Forbid something
        if spec.configuration.privileged:
            logger.warning("User %s tries to run privileged containers", user)
            raise ValueError("Running privileged containers is forbidden")
        # Set some service-specific properties
        if isinstance(spec.configuration, Service):  
            spec.configuration.https = True
        return spec

For more information on the plugin development, see the plugin example.