Inheritance
A pika config file can pull values from elsewhere and merge them into the resolved output that consumers see. The merging happens at read time, so the source is always the live remote value — no caching, no copy-paste.
Sources fall into two categories:
- Internal files — another pika config (or a specific variant of it).
- External resources — Vault, Kubernetes Secrets, Consul, etcd, AWS Secrets Manager / SSM, GCP Secret Manager, GCP Parameter Manager, Azure Key Vault, or plain HTTP.
External resources are configured once under Settings → External Resources and then referenced by name from any file's inheritance chain.
Inheritance entry shape
Each entry on a file is a small JSON object. Pick one of source (internal) or resource (external) per entry:
{
"resource": "my-vault",
"path": "myapp/database",
"paths": ["password", "host"],
"inject": "database.auth"
}| Field | Required | Description |
|---|---|---|
source | (one of 2) | Path to another pika config file. Append @variant to inherit from a specific variant. |
resource | (one of 2) | Name of an external resource defined under Settings. Use this for Vault, Kubernetes, Consul, etc. |
path | yes for resource | The resource-specific path: a Vault secret path, an etcd key, an S3 object key, etc. |
paths | no | Pick only specific keys out of the loaded data. Supports dot-notation (database.host) and wildcards (logging.*). |
inject | no | Nest the inherited data under this key path in the resolved output (e.g. database.auth). Supports dot-notation. |
format | no | When the resource returns an opaque string wrapped as {"value": "..."} (Consul / etcd / GCP / HTTP), set json, yaml, or toml to decode the inner payload before merge. Ignored for source entries — internal files carry their own meta.format. |
You manage inheritance entries from the Inherits section of a file in the UI. Order matters — later entries override earlier ones, and the file's own content overrides everything.
INFO
The mount field used to point at a raw filesystem mount; that feature was extracted out of pika. Legacy rows with "mount": "..." decode but the field is ignored at resolution time.
External resources
Each external resource has a name that you choose. That name is what resource: references. Pika supports the following backends — each has its own page with auth, configuration, and inheritance examples:
- HTTP — generic HTTP fetcher with basic / bearer / OAuth2 auth.
- Vault — HashiCorp Vault KV secrets.
- Kubernetes —
SecretandConfigMapobjects from the Kubernetes API. - Consul — Consul KV.
- etcd — etcd keys.
- AWS — Secrets Manager or SSM Parameter Store.
- GCP Secret Manager — opaque secret payloads.
- GCP Parameter Manager — server-side-templated parameter payloads.
- Azure — Key Vault.
- GitLab Variables — browse and edit group or project CI/CD variables.
Resource permissions
Every external resource carries its own permission switches, edited in the same form as its connection settings:
| Switch | Off means |
|---|---|
| Read values | No single-entry reads, no version history, and no inheritance — a file that inherits from the resource fails to resolve. |
| List | The inventory stays hidden; callers can still work with paths they already know. |
| Add new entries | Writes to paths that don't exist yet are rejected. |
| Change existing entries | Writes to paths that already exist are rejected. |
| Delete | Deletes are rejected. |
These are a ceiling, not a grant. A denied operation is refused before pika contacts the backend, for every caller — superadmin sessions, API tokens, MCP clients, and public endpoints alike. User capabilities (external.read / external.write) and token scopes can only narrow it further. A resource with everything switched off is effectively parked: the credentials stay configured, and Test connection still works so you can verify them.
Splitting add from change needs the backend to answer "does this path already exist" before writing. GitLab does; the others do not, so for them set both switches the same way — a mismatched pair rejects every write instead of guessing. The browser hides the actions a resource forbids, so New entry and Edit disappear rather than failing on submit.
Resources saved before these switches existed stay unrestricted.
Examples
Pull a database password out of Vault
Define an external resource named vault pointing at your Vault server, then on myapp/config add an inheritance entry:
{
"resource": "vault",
"path": "myapp/db",
"paths": ["password"],
"inject": "database.password"
}If the Vault secret returns { "password": "hunter2", "host": "..." }, the resolved config is merged with { "database": { "password": "hunter2" } }.
Inherit from another pika file
A prod variant that starts from the base config and only overrides a few fields:
{ "source": "myapp/config" }Or inherit from a specific variant:
{ "source": "myapp/config@staging" }Decode a string-wrapped Consul value
When a Consul KV value contains a JSON document but Consul returned it as a plain string, set format: json so pika decodes the inner payload before merging:
{
"resource": "consul",
"path": "config/myapp",
"format": "json",
"inject": "remote"
}Combine sources
[
{ "source": "shared/common" },
{ "resource": "k8s", "path": "default/secret/myapp", "inject": "secrets" }
]The base config's hand-edited fields override both inherited sources, so you can drop a single key into the file to change behaviour without touching either source.
Preview before saving
The Render panel in the UI shows the fully resolved output of a file with all inheritance applied. Use it to verify the chain produces the expected merged document before consumers fetch it.
The same data is available programmatically via:
curl -X POST -H "Authorization: Bearer $TOKEN" \
https://localhost:8080/api/v1/render/myapp/config