# References and imported folders

Two features keep a value in one place instead of copying it into every folder that needs it:

- A **reference** inside a value points at another secret. The value
  `postgres://${DB_USER}:${DB_PASSWORD}@db.internal/app` is filled in from `DB_USER` and
  `DB_PASSWORD` when your program reads it.
- An **imported folder** lends all its keys to another folder. Import `shared:/` into each
  environment's root, and every environment reads the keys you keep in `shared` as its own.

Both are resolved when the secrets are read, so changing the referenced secret or a key in the
imported folder changes what every reader gets, with no copy to update.

## Write a reference

In a secret's value, write one of:

| You write | It reads |
|---|---|
| `${KEY}` | `KEY` in the same folder |
| `${production.KEY}` | `KEY` at the root of the `production` environment |
| `${production.billing.stripe.KEY}` | `KEY` in the `/billing/stripe` folder of `production` |

To keep a literal `${` in a value, write `$${`. References can point at secrets that hold references
themselves, up to 5 deep.

When you save a value with a reference that doesn't resolve now (the key or folder doesn't exist
yet, or you can't read it), the editor lists it and asks before saving: choose **Save anyway** to
keep the value as written. A `.env` import shows the same warnings in its preview. A value with a
malformed reference, or one that would make references go in a circle, isn't saved: the editor
says why.

When you reveal a value, its references are marked, so you can tell what is filled in at read time.
The revealed value is the value as stored, references and all.

## Import a folder

Below the folder's secrets, **Imported folders** lists the folders this one imports, in order.

1. Choose **Edit imports**.
2. Pick the **Environment** and type the **Folder path** (`/` for the environment's root), then
   choose **Add folder**. A folder imports at most 20 folders, and can't import itself.
3. Use the arrows to change the order, or **Remove** to take a folder out.
4. Choose **Review changes**. The page shows the list **Now** and **After saving**, with what is
   added, removed or moved.
5. Choose **Save imports**.

The order matters: a later folder overrides an earlier one, and the folder's own secrets override
every import. Imports are one level: the folders an imported folder imports don't count.

### See where each key comes from

Under the list, each key that an import brings in shows every imported folder that has it. The
folder whose value is used is highlighted and the ones it overrides are struck through. **Value
used** says whether the folder's own secret wins or which import it comes from.

This list shows keys only; it reveals no value. An imported folder you can't read is named, and its
keys aren't listed. An import of a folder that no longer exists is marked **Folder not found** and
brings in nothing until the folder is created again.

## Preview the resolved values

Choose **Resolved values** to see what your program reads from this folder: every key, its own and
imported ones, with references filled in, and the folder each value comes from.

Like revealing, this is recorded in the [audit log](https://www.mocco.club/docs/en/articles/2yiscf-audit-log), with every folder it
read, and the values hide again after a minute.

If something doesn't resolve, the preview lists the key, the reference and why:

| Reason | What to do |
|---|---|
| No such secret | Add the key, or fix the name in the reference |
| No such environment or folder | Create it, or fix the path in the reference or the import |
| You can't read that folder | Ask an owner or admin for access, or point at another folder |
| The references go in a circle | Break the loop the preview shows, for example `A` → `B` → `A` |
| More than 5 references deep | Point closer to the final value |
| Not a valid reference | Fix the `${…}`, or write `$${` for a literal `${` |
| The resolved value is too large | Shorten the values it's made from |

A reference that doesn't resolve stays in the value as written, so your program sees `${KEY}`
rather than an empty string.
