Build a Module#

The following example demonstrates the creation of a new catalog module for a Postgres service.

Overview#

Library Overview#

Understanding the shape and functionality of the library will help conceptualize how modules are built.

Minitrino’s library is built around Docker Compose files and utilizes Docker’s ability to extend Compose files. The trino container is defined in the docker-compose.yaml file at the library root, and all nested module Compose files reference the root docker-compose.yaml file.

The library structure:

lib/
├── docker-compose.yaml
├── image
│   ├── Dockerfile
│   └── src
├── minitrino.env
├── modules
│   ├── admin
│   ├── catalog
│   ├── resources
│   └── security
├── snapshots
└── version

Create the Module Directory#

To start, create the module’s directory in the lib/modules/catalog/ directory:

mkdir lib/modules/catalog/my-postgres/
cd lib/modules/catalog/my-postgres/

Add Trino Resources#

All resources for a module go inside of the resources/ directory within the module’s directory (lib/modules/${type}/${module}/). Inside this directory, place Trino-specific resources into a cluster/ directory, then mount the resources to the Trino container defined in the root docker-compose.yaml file.

mkdir -p resources/cluster/

In the newly-created resources/cluster/ directory, add a properties file.

bash -c "cat << EOF > resources/cluster/postgres.properties
connector.name=postgresql
connection-url=jdbc:postgresql://postgres:5432/minitrino
connection-user=admin
connection-password=trinoRocks15
EOF"

Note: Passwords in default modules tend to be trinoRocks15. For consistency throughout the library, it is recommended to use this password.


Add the Docker Compose YAML#

In lib/modules/catalog/my-postgres/, add a Docker Compose file:

touch my-postgres.yaml

Note the naming convention: my-postgres.yaml. Giving the same root name of “my-postgres” to both the parent directory my-postgres/ and to the Docker Compose file my-postgres.yaml will allow the CLI to find the new module’s Compose file.

Next, add an environment file for the Postgres container. Non-Trino resources should go into their own directory, so create one for Postgres:

mkdir resources/postgres/

In the newly-created directory, add an environment file which will register the variables in the Postgres container when it is provisioned:

bash -c "cat << EOF > postgres.env
POSTGRES_USER=admin
POSTGRES_PASSWORD=trinoRocks15
POSTGRES_DB=minitrino
EOF"

This file will initialize Postgres with a database minitrino, a user trino, and a password trinoRocks15.

Add a Metadata File#

The metadata.json file exposes key information about the module. It is required for a module to work with the CLI.

In lib/modules/catalog/my-postgres/, add a metadata.json file:

bash -c 'cat << EOF > metadata.json
{
  "description": "Example Postgres catalog module",
  "incompatibleModules": [],
  "dependentModules": [],
  "enterprise": false
}
EOF'

Metadata Field Reference#

Required Fields#

  • description (string, required): Human-readable description of the module’s purpose and functionality.

    "description": "PostgreSQL catalog connector with async query support"
    

Optional Fields#

  • enterprise (boolean, optional, default: false): Indicates whether the module requires a Starburst Enterprise license (starburstdata.license). Set to true for Starburst-exclusive features.

    "enterprise": true
    
  • incompatibleModules (array of strings, optional): Lists modules that cannot be provisioned alongside this module due to conflicts (e.g., port collisions, conflicting configurations). Use ["*"] wildcard to indicate incompatibility with all other modules.

    "incompatibleModules": ["ldap", "oauth2"]
    
  • dependentModules (array of strings, optional): Specifies prerequisite modules that must be provisioned alongside this module. Minitrino will automatically include these during provisioning.

    "dependentModules": ["minio", "hive"]
    
  • versions (array of strings, optional): Defines version compatibility constraints for the module. Array can contain 0-2 items representing [minVersion, maxVersion]. Use "9999" to indicate no upper bound. Empty array [] means no version constraints.

    "versions": ["466", "9999"]  // Works with Trino/Starburst 466 and above
    "versions": ["443", "465"]   // Works only with versions 443-465
    "versions": []               // No version constraints
    
  • dependentClusters (array of objects, optional): Advanced feature for multi-cluster orchestration. Defines additional clusters that should be automatically provisioned alongside the primary cluster. Used by modules like starburst-gateway and stargate for federated query scenarios.

    Each object requires:

    • name (string): Unique name for the dependent cluster

    • modules (array of strings): Modules to provision in the dependent cluster

    • workers (number): Number of worker nodes (0 for coordinator-only)

    • env (object): Environment variables specific to this cluster

    "dependentClusters": [
      {
        "name": "stargate-remote",
        "modules": ["hive", "password-file"],
        "workers": 0,
        "env": {
          "__PORT_MINITRINO": "60801",
          "CONFIG_PROPERTIES": "http-server.process-forwarded=true"
        }
      }
    ]
    

Metadata Schema Validation#

All metadata files are validated against a JSON schema during CLI operations. If validation fails, Minitrino will provide detailed error messages indicating which fields are invalid.

Example: Complete Metadata File#

{
  "description": "Iceberg catalog with REST metadata management and S3 storage",
  "incompatibleModules": [],
  "dependentModules": ["minio"],
  "enterprise": false,
  "versions": ["443", "9999"],
  "dependentClusters": []
}

Viewing Metadata#

The metadata can be exposed via the modules command:

minitrino modules -m ${module}

Add a Readme File#

This step is not required for personal development, but it is required prior to merging modules into the master branch.

In lib/modules/catalog/my-postgres/, add a readme.md file:

touch readme.md

This file should contain an overview of the module.

Review Progress#

The resulting directory tree should look like this (from the lib/modules/catalog/ directory):

my-postgres
├── metadata.json
├── my-postgres.yaml
├── readme.md
└── resources
    ├── cluster
       └── postgres.properties
    └── postgres
        └── postgres.env

Configure the Docker Compose YAML File#

We will now define the my-postgres.yaml Docker Compose file:

services:
  minitrino:
    volumes:
      - ./modules/catalog/my-postgres/resources/cluster/postgres.properties:/mnt/etc/catalog/postgres.properties:ro

  postgres:
    image: postgres:${POSTGRES_VER}
    container_name: postgres-${CLUSTER_NAME}
    env_file:
      - ./modules/catalog/my-postgres/resources/postgres/postgres.env
    ports:
      - ${__PORT_POSTGRES}:5432
    volumes:
      - postgres-data:/var/lib/postgresql/data
    labels:
      - org.minitrino.root=true
      - org.minitrino.module.catalog.my-postgres=true

volumes:
  postgres-data:
    labels:
      - org.minitrino.root=true
      - org.minitrino.module.catalog.my-postgres=true

Important Implementation Details: Paths and Labels#

Path References for Volumes and Build Contexts#

Volumes mounted in Docker Compose files are not relative to the Compose file itself, they are relative to the base docker-compose.yaml file in the library’s root directory. This is because the CLI extends Compose files, meaning that all path references in child Compose files need to be relative to the positioning of the parent Compose file.

Additional information can be found about extending Compose files in the Docker docs.

Minitrino Docker Labels#

All Minitrino Docker Compose files use labels. The labels associate containers, volumes, and images with Minitrino and allow the CLI to target those objects when executing commands.

Applying labels to the minitrino container is only necessary when minitrino is the only service defined in the Compose file. The biac module is an example of this.

Labels should always be applied to the following objects:

Labels should be defined in pairs of two. The naming convention is:

  • The standard Minitrino resource label: org.minitrino.root=true

  • A module-specific resource label: org.minitrino.module.${MODULE_TYPE}.${MODULE_NAME}=true

    • Module type can be one of: admin, catalog, or security

    • This applies a unique label to the module, allowing it to be isolated when necessary

In Compose files where multiple containers are defined, all containers should be labeled with the same label sets (as seen in the hive module’s Compose file).


Note: The example above already includes a named volume (postgres-data) in the Compose file. Named volumes should always have labels applied to them, as shown in the example.

Test the New Catalog#

Provision the new catalog with the CLI:

minitrino -v provision -m my-postgres

Open a shell session in the minitrino container and run some tests:

docker exec -it minitrino-default bash
trino-cli

trino> SHOW CATALOGS;

Note: If you provisioned with a custom cluster name (e.g., --cluster my-cluster), replace minitrino-default with minitrino-my-cluster.