Preview environments
Temporary copies of an environment for testing changes with real data.
A preview environment is a temporary copy of an existing environment. By default, it runs the same services with their own URLs and their own network namespace, on top of its own copy of the parent’s stateful data, so a change can be tested end to end without touching the parent.
How previews are created
- Per pull request - with the GitHub integration connected, Specific creates a preview environment for each open pull request, keeps it up to date as new commits are pushed, and posts its URL back on the PR. Connect GitHub from the dashboard.
- Manually - deploy one on demand with
specific deploy --preview.
Preview environments are ephemeral: pull-request previews are removed when the PR is closed or merged, and a preview can be given an expiry, after which Specific cleans it up automatically.
Run specific status to list every environment and its env_... ID, including preview environments, or specific status --previews to see whether previews are enabled, whether GitHub PR previews are configured, and whether PRs need a label. Target a preview with --environment on commands that take one.
Some projects require the specific:preview label on a pull request before Specific creates its preview. With label gating on, adding the label starts the preview and removing it tears the preview down.
Redeploying a preview
To update an existing preview, for example with a changed config value, target it directly:
specific deploy --environment env_... --config FEATURE_FLAG=true
--preview always creates a new manual preview, so do not combine it with --environment.
Preview builds reuse the parent environment’s build cache, so the first deploy of a preview is fast when it shares dependencies and build steps with the parent.
Partial previews
For projects with several services, you can turn on Partial previews in the parent environment’s dashboard settings. New previews then deploy only the services affected by your changes and connect unchanged services to the parent environment.
This makes previews faster and uses fewer resources, but they are not fully isolated from the parent. Specific clones databases and buckets used by the affected services, while resources used only by unchanged services stay in the parent environment. If a change does not affect any service, Specific skips creating an empty preview.
What’s copied from the parent
A full preview branches off a parent environment and starts from its data. Each resource is forked in the way that’s fastest for that service:
- Postgres databases are branched - an instant, copy-on-write branch.
- Object storage buckets are forked.
- Volumes are cloned - an instant, copy-on-write copy of the parent volume.
The preview gets its own isolated database, buckets, and volumes; writing to them never affects the parent. Partial previews clone only the resources used by services running in the preview.
A volume clone is an exact replica of the parent’s on-disk data (uploads, caches, and search indexes alike), so the preview’s service boots on it exactly as it would after a restart, with no extra configuration.
Secrets and config
A preview also inherits the parent environment’s secrets and config values, so its services start with the same configuration the parent runs with - nothing to re-enter.
To give previews a different value for a specific secret or config - say a sandbox API key or a test-only endpoint - set a preview override on the parent environment’s Secrets and config page in the dashboard. Every preview branched from that environment then uses the override for that value while still inheriting everything else. See Secrets and config.
Observability
Previews stream logs and metrics exactly like long-lived environments. Query them by targeting the preview with --environment:
specific query --environment preview-a1b2c3d4 \
"SELECT Timestamp, Body FROM observability.logs ORDER BY Timestamp DESC LIMIT 50"
See Observability for the full query reference.
Inspecting a preview from a fresh checkout
CI runners and fresh clones have no .specific/project_id, so specific status cannot find the project. Use the deployment ID from the PR comment directly:
specific deployment show <depl_...> --output --format json
To use specific status or --environment from such a checkout, run specific project list and save the chosen proj_... ID to .specific/project_id.
Common questions
Does a preview share anything with the parent?
A full preview shares nothing: it has its own services, database branch, buckets, volumes, Redis and Temporal instances, and URLs. A partial preview shares the services it did not change, and the resources only those services use, with the parent.
Can a preview modify production data?
No. Writes go to the preview’s own copies. In a partial preview, an unchanged service still runs in the parent and keeps using the parent’s data, which is why partial previews skip crons that would write to it.
How is a preview cleaned up?
Pull-request previews are removed when the PR is closed or merged. Manual previews expire after their expiry passes and are removed by a scheduled cleanup. Deleting a preview deletes its database branch, buckets, and volumes with it.
Can I give a preview different secrets?
Yes. Set a preview override on the parent environment’s Secrets and config page in the dashboard, and every preview branched from it uses that value.