Drone CI’s environment and secrets directives are your primary tools for injecting configuration and sensitive data into your build steps, but the devil is in the details of how they interact and where they’re defined.

Let’s see it in action. Imagine a simple .drone.yml that needs to access a GitHub token and a database password:

kind: pipeline
type: docker
name: example

steps:
- name: build
  image: alpine
  commands:
    - echo "Building..."
    - echo "My GitHub token is: $GITHUB_TOKEN"
    - echo "My database password is: $DB_PASSWORD"
  environment:
    MY_BUILD_VAR: "hello"

- name: deploy
  image: alpine
  commands:
    - echo "Deploying..."
    - echo "My GitHub token is: $GITHUB_TOKEN"
    - echo "My database password is: $DB_PASSWORD"
  environment:
    MY_DEPLOY_VAR: "world"

secrets:
- name: github_token
  default: "fallback_token" # Only used if repo/user secret isn't set
- name: db_password

And assume you’ve set up these secrets in your Drone UI (or via API/CLI):

  • Repository level: github_token with value ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Repository level: db_password with value s3cr3tP@ssw0rd!

When this pipeline runs, the output for the build step will look like this:

+ echo Building...
Building...
+ echo My GitHub token is: $GITHUB_TOKEN
My GitHub token is: ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ echo My database password is: $DB_PASSWORD
My database password is: s3cr3tP@ssw0rd!
+ echo MY_BUILD_VAR=hello
MY_BUILD_VAR=hello

And for the deploy step:

+ echo Deploying...
Deploying...
+ echo My GitHub token is: $GITHUB_TOKEN
My GitHub token is: ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ echo My database password is: $DB_PASSWORD
My database password is: s3cr3tP@ssw0rd!
+ echo MY_DEPLOY_VAR=world
MY_DEPLOY_VAR=world

Notice how both GITHUB_TOKEN and DB_PASSWORD are available in both steps, even though they were only declared in the top-level secrets block. This is because top-level secrets are globally available to all steps within the pipeline.

The environment directive within a step is for non-sensitive, build-specific variables. MY_BUILD_VAR and MY_DEPLOY_VAR are only set within their respective steps. If you tried to access MY_BUILD_VAR in the deploy step, it would be empty.

Drone’s secret handling has a hierarchy. Secrets can be defined at the user level, repository level, or pipeline level. The most specific definition wins. If you have a github_token set at the repository level and also at the user level, the repository-level one will be used for pipelines within that repository. If a default value is provided in the .drone.yml and no secret is found at the user or repository level, the default value will be used. This is what happens if you define github_token in .drone.yml with a default but don’t set it in the UI or API.

The environment directive is processed after secrets. This means if you define a variable in environment with the same name as a secret, the environment variable will overwrite the secret for that specific step. This is generally not recommended for sensitive data but can be useful for overriding non-sensitive configuration.

For example, if the build step had this:

  environment:
    MY_BUILD_VAR: "hello"
    GITHUB_TOKEN: "local_override_token" # This would override the secret for this step

The GITHUB_TOKEN printed in the build step would be local_override_token, while in the deploy step it would still be the repository-level secret.

When you define secrets in the .drone.yml, they are typically meant to be references to secrets stored elsewhere (user/repo level). If you want to inject a secret directly into the .drone.yml without storing it in the Drone UI, you’d use the data field of the secret definition, which is then base64 encoded. However, this is strongly discouraged for any sensitive information that shouldn’t be in version control.

The most powerful aspect of Drone’s environment and secrets is their scope and the ability to override. You can set global secrets that apply everywhere, and then fine-tune them per repository or even per pipeline. The environment directive within a step provides a way to inject completely custom, non-sensitive variables that are scoped only to that step.

The next thing you’ll likely run into is how to manage secrets across multiple pipelines or how to use them in conditional logic within your pipeline.

Want structured learning?

Take the full Drone course →