Skip to main content

Create, Copy, and Merge Environments

Create a Permit.io environment in the dashboard or with the Permit API, and copy or merge policy between environments to promote changes from development to production. This page is for developers and admins who manage the projects and environments of a Permit workspace. For what projects and environments are, see Projects and environments.

Prerequisites​

Create an environment in the dashboard​

  1. In the Permit dashboard, open the Projects screen and find your project.
  2. Click New Environment.
  3. Fill in the environment details and save.

The new environment appears as a card under your project. The card menu has Copy API Key, Rotate API Key, Edit Environment, and Delete Environment.

Create an environment with the API​

Send a POST request to /v2/projects/<project-id>/envs with the environment key and name. Replace <project-id> with your project ID or key and <api-key> with your organization-level or project-level API key:

curl 'https://api.permit.io/v2/projects/<project-id>/envs' \
-H 'authorization: Bearer <api-key>' \
-H 'Content-Type: application/json' \
--data-raw '{"key":"new-env-name","name":"New Env Name"}'
API key level

The Create Environment API accepts an organization-level or project-level API key. See API key levels.

The response contains the new environment object. To confirm, list the environments of the project with the List Environments API, or open the Projects screen in the dashboard. For all request fields, see Create Environment in the API reference.

Default roles for new resources​

An environment can create a default set of roles (Admin, Editor, and Viewer) with predefined permissions every time a workspace member creates a resource in the environment, for example in the Policy Editor. Resources created through the Permit API with an API key don't get default roles.

Default role creation is off by default. Turn default role creation on when you create an environment with the API, or later with the toggle in the Policy Editor settings.

Default settings of a new environment​

The environment settings that control default roles have this shape. default_resource_actions lists the actions of each new resource, and default_resource_permissions lists the permissions of each default role:

{
"default_resource_actions": ["create", "read", "update", "delete"],
"default_resource_permissions": {
"admin": ["create", "read", "update", "delete"],
"editor": ["create", "read", "update"],
"viewer": ["read"]
},
"enable_default_roles": false
}
note

enable_default_roles defaults to false. With enable_default_roles set to false, Permit doesn't create default roles for new resources.

Toggle default role creation in the UI​

  1. Open the Policy Editor in the Permit dashboard.
  2. Click the settings button of the Policy Editor.
  3. Use the default roles toggle:
    • On: Permit creates the default roles (Admin, Editor, Viewer) with their predefined permissions for each new resource in the environment.
    • Off (default): Permit doesn't create default roles. You create roles yourself.

Turn on default roles with the API​

To turn on default role creation, set settings.enable_default_roles to true in the Create Environment request body:

curl 'https://api.permit.io/v2/projects/{project_id}/envs' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data-raw '{"key":"new-env-name","name":"New Env Name", "settings": {"enable_default_roles": true}}'

To turn off default role creation explicitly, set settings.enable_default_roles to false:

curl 'https://api.permit.io/v2/projects/{project_id}/envs' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data-raw '{"key":"new-env-name","name":"New Env Name", "settings": {"enable_default_roles": false}}'

In these samples, replace {project_id} with your project ID or key and API_SECRET_KEY with your organization-level or project-level API key.

Copy and merge environments​

You can copy an environment into a new environment, or into an existing environment (a merge). Copy and merge let you manage policy changes, such as a new resource, role, or condition set, in a controlled way. For example, to test a new resource, copy the production environment to a development environment, add the resource in development, test it, and merge development back into production.

In the diagram, the Production environment has a File resource and an Editor role. Production is copied into a Development environment, where a Folder resource and an Admin role are added. After testing, Development is merged back into Production.

This flow lets you promote policy changes between environments the same way a CI/CD pipeline promotes code. See Policy life cycle with Permit.

Copy rules:

  • Copy and merge work only between environments in the same project. Copying across projects or workspaces isn't allowed.
  • To copy into a new environment, the API key or member needs write access to the project.
  • To copy into an existing environment, the API key or member needs write access to the target environment.
  • To delete condition sets the source doesn't have, the API key or member also needs permission to delete condition sets in the target environment.

Copy an environment with the API​

Send a POST request to /v2/projects/{project_id}/envs/{env_id}/copy, where {env_id} is the source environment. Set target_env.new to create an environment, or target_env.existing to the ID or key of an existing environment to merge into.

curl --location 'https://api.permit.io/v2/projects/{project_id}/envs/{env_id}/copy' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data '{
"target_env": {
"new": {
"key": "prod",
"name": "production"
}
}
}'

For all request fields, see Copy Environment in the API reference.

Copy a large environment in the background​

Copying a large environment can take time. The background Copy Environment API (/copy/async) runs the copy asynchronously, returns HTTP 202 Accepted with a task_id, and lets you fetch the result later.

curl --location 'https://api.permit.io/v2/projects/default/envs/staging/copy/async' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data '{
"target_env": {
"new": {
"key": "prod",
"name": "production"
}
}
}'

To wait for the task and read its result, see Background APIs.

Objects that copy and merge include​

Copy and merge apply only to policy objects, such as resources, roles, and condition sets. Directory objects, such as users, tenants, and resource instances, are not copied or merged.

When you copy an environment, Permit copies the checked objects below:

  • Resource
  • Resource Actions
  • Resource Action Groups
  • Resource Attributes
  • Resource Roles
  • Resource Relations
  • Roles
  • Role Permissions
  • Role Derivations
  • Role Hierarchy
  • Condition Sets
  • User Sets
  • Resource Sets
  • Condition Sets Rules
  • Condition Sets Inheritance (details)
  • Custom Policies (details)

Custom policies in copied environments​

When you use GitOps with a custom Git repository, copying an environment copies all files in the source environment's branch into the new environment's branch, including all custom .rego policy files.

Copy into an environment protected by a Policy Guard​

When the target environment is protected by a Policy Guard, the copy checks every guarded object it would change or delete, the same way the API does when you change that object directly. If the guard forbids the change, the copy fails with 403 Forbidden and nothing is copied. Objects the copy leaves unchanged, and new objects it creates, don't need the guard's permission, so promoting an environment whose guarded objects are already identical still succeeds.

Conflict strategy for merges​

When you merge into an existing environment, a conflict occurs if the same object, such as a resource or role, was changed in both environments.

In the diagram, an Admin role is added to Production after Production was copied into Development. Development also has an Admin role, so merging Development back into Production causes a conflict on the Admin role.

Set conflict_strategy in the copy request body to choose how Permit resolves conflicts:

conflict_strategyResult
fail (default)The merge fails, Permit rolls back the entire merge, and the target environment keeps its existing objects.
overwritePermit replaces the existing object in the target environment with the object from the source environment. For a condition set, this includes its parent condition set.

Neither strategy deletes a condition set that exists only in the target environment. To delete those, see Delete condition sets the source doesn't have.

Condition set hierarchy in a copy​

A copied condition set keeps its parent. A child condition set matches only the users or resources that also match every ancestor, so copying it without its parent would grant more than the source environment does.

  • If scope copies a condition set but leaves out its parent, the copy fails with 409 Conflict and nothing is copied. Change scope so it also copies the parent, or so it leaves out the child.
  • Copying again with "conflict_strategy": "overwrite" re-parents condition sets that already exist in the target environment to match the source environment, including removing a parent the source no longer has.
  • If the source environment's hierarchy contains a cycle, or a parent of a different type or resource than its child, the copy fails with 406 Not Acceptable and nothing is copied.

Exclude or include objects in a copy​

Set scope in the copy request body to exclude or include specific objects. scope accepts resources, roles, user_sets, resource_sets, and custom_policies, each with include and exclude lists.

curl --location 'https://api.permit.io/v2/projects/{project_id}/envs/{env_id}/copy' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data '{
"target_env": {
"new": {
"key": "prod",
"name": "production"
}
},
"scope": {
"roles": {
"exclude": ["*"]
},
"resources": {
"include": ["folder", "file"]
},
"resource_sets": {
"exclude": ["test*"]
},
"user_sets": {
"exclude": ["canada_users"]
},
"custom_policies": {
"include": ["*.rego"]
}
}
}'

include and exclude match object keys. * is the only wildcard and matches any run of characters, other characters match themselves, and matching is case-sensitive. An object is copied when its key matches any include pattern (or include is empty) and no exclude pattern. custom_policies patterns are different: they match file paths in the environment's policy branch and follow Unix filename pattern matching.

Delete condition sets the source doesn't have​

When you merge into an existing environment, set "delete_target_only_condition_sets": true to delete the target environment's condition sets that the source environment doesn't have. Use it to promote a removal or a key rename from one environment to the next. It is off by default.

curl --location 'https://api.permit.io/v2/projects/{project_id}/envs/{env_id}/copy' \
-H 'authorization: Bearer API_SECRET_KEY' \
-H 'Content-Type: application/json' \
--data '{
"target_env": {
"existing": "prod"
},
"conflict_strategy": "overwrite",
"delete_target_only_condition_sets": true
}'

Permit deletes a target condition set only when all of these are true:

  • scope selects it, using the same matching as the copy.
  • The source environment has no condition set with the same key, whether or not scope selects that key in the source.
  • It isn't an autogenerated condition set, such as the user set Permit creates for a role.
  • If it is a resource set, its resource is copied.

Deleting a condition set also deletes its child condition sets and its condition set rules. If deleting a selected condition set would also delete a child condition set that wouldn't be deleted on its own, the copy fails with 409 Conflict and nothing is deleted.

The deletion needs permission to delete condition sets in the target environment.

delete_target_only_condition_sets has no effect when you copy into a new environment.

Customize the GitOps branch name​

When you create or copy an environment, you can set the name of the Git branch that stores the environment's policy. A custom branch name requires an active policy repository on the project.

Set custom_branch_name when you create the environment:

curl 'https://api.permit.io/v2/projects/{project_id}/envs' \
-H 'authorization: Bearer {API_SECRET_KEY}' \
-H 'Content-Type: application/json' \
--data-raw '{"key":"new-env-name","name":"New Env Name", "custom_branch_name": "new-env-branch-name"}'

Your policy repository then has a branch named new-env-branch-name for the new environment.

You can also set custom_branch_name in target_env.new when you copy into a new environment. To move an existing environment to a different branch, update the environment with a PATCH request:

curl 'https://api.permit.io/v2/projects/{project_id}/envs/{env_id}' -X 'PATCH' \
-H 'authorization: Bearer {API_SECRET_KEY}' \
-H 'Content-Type: application/json' \
--data-raw '{"custom_branch_name": "new-env-branch-name"}'

Next steps​