---
url: /en/build/create-plugin.md
description: >-
  Step-by-step guide for developing a Cloud Native Build plugin as a Docker
  image, covering parameter design, input handling, image building, and
  publishing to the plugin registry.
---
In `Cloud Native Build`, a plugin is essentially a Docker image.
Below is how to develop an image plugin from scratch using Bash.

This example plugin prints `hello world`. Basic Docker knowledge is assumed.

## Designing the Plugin

### Parameter Design

Design the plugin parameters:

* `text`: The text content to be printed to the console

These parameters are passed to the container as environment variables, converted to uppercase with a `PLUGIN_` prefix.

### Supported Parameter Types

Parameter types support `string`, `number`, `boolean`, `one-dimensional array`, and `plain object`.

Configuration example:

```yaml title=".cnb.yml"
main:
  push:
    - stages:
        - name: hello world
          image: cnbcool/hello-world
          settings:
            text: hello world
            boolean: true
            number: 123
            array: [hello, world]
            map:
              key: value
```

These parameters are converted to the following environment variables inside the container:

```text
PLUGIN_TEXT='hello world'
PLUGIN_BOOLEAN='true'
PLUGIN_NUMBER='123'
PLUGIN_ARRAY='hello,world'
PLUGIN_MAP='{"key":"value"}'
```

* Arrays are comma-separated when passed to the container
* Plain objects are converted to JSON strings

If the parameter structure is overly complex, consider storing them in a file and loading at runtime,
simplifying the design, or splitting into multiple plugins.

## Writing the Script

Write a Bash script to print the parameters:

```bash
#!/bin/sh
echo "$PLUGIN_TEXT"
```

## Building the Plugin Image

The plugin is packaged as a `Docker` image for distribution.
Create a `Dockerfile` to package the script and set it as the `Entrypoint`.

```bash
FROM alpine

ADD entrypoint.sh /bin/
RUN chmod +x /bin/entrypoint.sh

ENTRYPOINT /bin/entrypoint.sh
```

Build the image:

```bash
docker build -t cnbcool/hello-world .
```

## Testing the Plugin

Test the plugin locally using `docker run`, passing parameters via environment variables:

```bash
docker run --rm \
  -e PLUGIN_TEXT="hello world" \
  cnbcool/hello-world
```

### Testing Filesystem Access

The plugin can read the build process workspace directory. By default,
the build directory is mapped to a plugin directory and set as the workspace:

```bash
docker run --rm \
  -e PLUGIN_TEXT="hello world" \
  -v $(pwd):$(pwd) \
  -w $(pwd) \
  cnbcool/hello-world
```

## Exporting Variables

After a plugin finishes execution, you can output results using the
`##[set-output key=value]` format and then use the pipeline's
[`exports`](./grammar.md#job-exports) to export them as environment
variables for subsequent tasks.

### Example: Exporting a GREETING Variable

Suppose the plugin needs to export `hello world` as the variable `GREETING` for use by a subsequent Job.

**1. Modify the plugin script to output a custom variable:**

```bash title="entrypoint.sh"
#!/bin/sh
echo "$PLUGIN_TEXT"

# Output a custom variable for exports
printf '##[set-output greeting=%s]\n' "$PLUGIN_TEXT"
```

> `##[set-output key=value]` is parsed by CI into the Job's `result` object,
> which can then be exported as environment variables via `exports`.

**2. Use `exports` in the pipeline to export the variable, and reference it in subsequent tasks:**

```yaml title=".cnb.yml"
main:
  push:
    - stages:
        - name: hello world
          image: cnbcool/hello-world
          settings:
            text: hello world
          exports:
            greeting: GREETING
        - name: use greeting
          script: echo $GREETING
```

After running, the second Job will output `hello world`.

::: tip More Usage
`exports` supports exporting script execution results (`code`, `stdout`,
`stderr`, `info`) and built-in task return values. See
[Environment Variables - Exporting Environment Variables](./env.md#export-environment-variables)
for details.
:::

## Publishing the Plugin

A plugin is a Docker image — publishing a plugin means publishing the image.

You can publish to the built-in
[Artifact Registry](../artifact/docker.md) of Cloud Native Build,
or to Docker Hub for global availability.

### Pushing the Image

```bash
docker push cnbcool/hello-world
```
