Workplace Structure

Learn how to structure your projects and configs most effectively inside a workplace.

There are many ways you could potentially model your project structure inside your workplace. This guide will walk you through the most typical way to structure your projects inside your workplace to make sure you're taking advantage of our features most effectively.

Project Naming

The best way to think of a project is to think of it as an encapsulated application service. For example, you might have two applications (e.g., AcmeWidgets and OmniCommerce) – each with two services: worker and backend. Each of those services should map to a separate project. Rather than using the overarching application name as the project name, you would use that in the project name as a namespace along with the service name. In this scenario, you might have projects named as follows:

  • acme-widgets-worker
  • acme-widgets-backend
  • omni-commerce-worker
  • omni-commerce-backend

Doing this allows you to have more fine-grained access controls over your secrets.

🚧

A common mistake when structuring projects is to name them after a company department, overarching application name, or even third-party service and then use environments under the project to hold secrets for different services related to that category or application. An example of this anti-pattern would be a situation where you have an application named AcmeWidgets that was comprised of a Worker and Backend service. Creating a project named acme-widgets and then having environments named worker and backend would be a textbook example of setting this up incorrectly.

Environment Naming

Environments should typically map to some kind of deployment environment (e.g., dev, stg, ci, qa, prd, etc.). The general design behind environments is that the project owning an environment maps to a single application and the majority of the secret keys in each config (e.g., STRIPE_API_KEY) will be the same across the configs in that environment (e.g., STRIPE_API_KEY will be one value in dev, another value in stg, and yet another in prd). This design is what drives our config compare feature and the features that allow you to copy a secret to other configs when saving. The further outside this model you go when structuring your projects, the more rough-edges you'll likely run into further down the road.

If you find yourself naming environments after application or service names or end up needing more than our limit of 15 environments per project, that's a good sign that you may be structuring things wrong!

Shared Projects

In many cases, you might find that you need to share certain secrets across many applications. The best way to accomplish this is to create shared projects that contain those secrets. You can name these either after the application that has secrets you need to share to multiple other services or after a third-party service (e.g., AWS credentials, GitHub credentials, etc.).

Shared Application Secrets

Let's say you have an application called AcmeWidgets. As before, that application has two separate services: worker and backend. Those two services each have a set of secrets that they share (e.g., STRIPE_API_KEY). The best way to handle this is to create four projects:

  • acme-widgets-worker
  • acme-widgets-backend
  • acme-widgets-shared

Inside the acme-widgets-shared project, add the appropriate STRIPE_API_KEY secret for each environment (e.g., dev, stg, prd). Now, in each of the other acme-widgets-* projects, create a new STRIPE_API_KEY secret and use cross-project secret referencing (e.g., so the value for STRIPE_API_KEY in the dev environment for acme-widgets-worker would be ${acme-widgets-shared.dev.STRIPE_API_KEY}).

Using this approach will allow you to easily update the secret values in the shared project without needing to manually update each of your other projects. If you want more access control over these, you might have an acme-widgets-shared and acme-widgets-credentials project where everything under the shared project is less sensitive and everything under the credentials project is more sensitive.

🚧

Keep in mind that when updating a secret you can only reference secrets for projects/environments you have access to. However, when reading secrets, any configured references will be resolved regardless of the reader's permissions.

For example, a user who performs a doppler secrets download on a config they have access to (let's say acme-widgets-worker.dev) would see the resolved values of all secret references in that config regardless of whether they're to projects or configs that user has access to.

Shared Third-party Credentials

In some scenarios, you might have some third-party credentials that are used across many different applications. In a scenarios like that, it's common to create projects with a global- namespace (e.g., global-credentials). This allows you to use a similar approach as described above, but across many applications.

Alternate Naming Pattern

Another naming convention that might work better for you than what's described above would be having a single project per application and then naming branch configs after the services that compose that application. For example, you might have an application named AcmeWidgets that's composed of a worker and backend service.

Under this pattern, you would have a single acme-widgets project. Under that project, you would have a dev, stg, ci, and prd environment. Under each of those environments, you would have a branch config for each service. For example, you might have dev_worker and dev_backend along with prd_worker and prd_backend. You would then put any shared secrets in the root config (i.e., dev, stg, prd, etc.). Those secrets would be inherited by the branch configs. In those branch configs you can then override or add any additional secrets that you may need. If you have cross-project secrets (e.g., STRIPE_API_KEY), then you might still use a global-credentials project that you would reference via secret references in the root configs of your acme-widgets project.

The downside to this approach is that you lose some access control granularity since project permissions are setup on a per environment level – so there would be no way to provide someone access to a single service's secrets. You could provide them access to the dev environment and then they'd have access to all services with branch configs under that environment.