# Migrating from Legacy

<admonition type="info">

Depending on which client-side SDK you use, the custom permissions checking processes may not be implemented yet and could affect user experience. If you use our client SDKs, we recommend waiting to migrate until there is complete front end support, or test this thoroughly in development first. Updates will be posted here as we add more support.

</admonition>

The migration process is pretty straightforward and mostly automated, but you should consider these facts before you pull the trigger:

1. Make sure backend of your app does not explicitly sets "permission_version" field to "v1" using UpdateApp API endpoint. This will cause your app to rollback to previous version of permission system

2. There are some permissions properties which should no longer be used on v2 so it is good to understand how you are using them today

3. "Permissions" field in UpdateChannelType will not affect new permission system. This field is kept for backward compatibility and it allows you to roll back to version 1 in case you changed your mind

4. Do not use `User.role` , `ChannelMember.channel_role` to determine user capabilities. This kind of check is usually fragile and in case of configuration change, UI will not be representative of the new settings

5. Do not use `ChannelMember.role` as it is displaying inconsistent values. This field is kept for backwards compatibility only

6. Option `user_search_disallowed_roles` only works with permissions v1. To control set of users who can perform user search you should use application-level permission grants ( `.app` scope)

7. If you plan to use custom permissions, make sure your client code does not rely on direct role comparisons. Please see [Channel Capabilities](/chat/docs/<framework>/channel_capabilities/) page for more info

## Prerequisites

In order to use version 2 of permissions system, make sure you use compatible version of SDK

| SDK          | Minimum version |
| ------------ | --------------- |
| React        | v7.0.0          |
| React Native | v4.0.0          |
| Angular      | v2.2.0          |
| Android      | v4.27.0         |
| iOS          | v4.0.0          |
| Flutter      | v3.4.0          |
| Unreal       | v1.0.0          |
| Unity        | v1.0.0          |

<admonition type="info">

iOS and Unreal SDKs don't support Channel Capabilities yet

</admonition>

We strongly recommend to regularly update your SDK dependencies since they constantly improve user experience, resolve bugs and add support for new features

## How to migrate

We provide two options for performing a migration

### Using Dashboard

When you open a Chat application overview for the app that uses older version of permissions, you will see a popup suggesting you to perform an upgrade.

![](https://getstream.imgix.net/docs/95c585a9-cd9b-4f6e-846c-8e490f40918e.png?auto=compress&fit=clip&w=800&h=600)

Click "Upgrade" and wait until the page refreshes. Now you should be able to access new "Roles and Permissions" page to set up the permission settings.

You can also navigate directly to the "Roles & Permissions" page under chat settings and click "Upgrade" on the prompt shown there.

![](https://getstream.imgix.net/docs/2bacc292-87f6-4037-9fad-77be2dc09a24.png?auto=compress&fit=clip&w=800&h=600)

This upgrade option translates old permission settings the new system automatically, but we encourage you to visit "Roles and Permissions" page to double check that the configuration is correct.

### Using API

In order to migrate to permissions "v2" you have to perform exactly this API call to UpdateApp API endpoint:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.updateAppSettings({
  permission_version: "v2",
  migrate_permissions_to_v2: true,
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->updateAppSettings([
 'permission_version' => 'v2',
 'migrate_permissions_to_v2' => true,
])
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.update_app_settings(permission_version="v2", migrate_permissions_to_v2=True)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
App.update().permissionVersion(App.PermissionVersion.V2).migratePermissionsToV2(true).request();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var settings = new AppSettings
{
  MigratePermissionsToV2 = true,
  PermissionVersion = PermissionVersion.V2,
};
await client.UpdateAppSettings(settings);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# require 'stream-chat'

client.update_app_settings(permission_version: 'v2', migrate_permissions_to_v2: true)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
doMigrate := true
settings := &AppSettings{
	MigratePermissionsToV2: &doMigrate,
	PermissionVersion:   "v2",
}

resp, err := client.UpdateAppSettings(ctx, settings)
```

</codetabs-item>

</codetabs>

`permission_version` field controls which permission system version is active. You can switch back and forth without providing any extra fields, but in order to convert all your existing configuration, you should provide `"migrate_permissions_to_v2": true` . When this flag is present, Chat API translates v1 configuration to v2 for you which ensures that your app functions properly without any interruptions. You can always switch back to v1, but configuration translation only works one way. You can also prepare permissions v2 configuration manually and switch to the new version without providing `migrate_permissions_to_v2` flag

<admonition type="warning">

We recommend you to take a good look at the resulting grants configuration and make sure that all permissions there are correct. Even better if you can test these configurations in development before updating production

</admonition>

## How to switch back

In case something goes wrong for you, you can switch back to legacy permission system:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.updateAppSettings({
  permission_version: "v1",
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->updateAppSettings([
 'permission_version' => 'v1',
])
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.update_app_settings(permission_version="v1")
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
App.update().permissionVersion(App.PermissionVersion.V1).request();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var settings = new AppSettings
{
  PermissionVersion = PermissionVersion.V1,
};
await client.UpdateAppSettings(settings);
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.update_app_settings(permission_version: 'v1')
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
settings := &AppSettings{
	PermissionVersion: "v1",
}

resp, err := client.UpdateAppSettings(ctx, settings)
```

</codetabs-item>

</codetabs>

## New Global Roles

_For multi-tenant applications only_

Once you migrate to v2 permissions there will be two new roles available. These roles allow users to be Admins or Moderators across all teams. Previously, all users had to belong to a team and could only access channels and messages belonging to the same teams. These new roles allow access to all teams data and are important for users of the Stream Dashboard.

To change the role of Admin Users to Global Admin, or to change the role of Moderators to Global Moderator, you can use UpdateUser API endpoint:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.partialUpdateUser({
  id: "james_bond",
  set: { role: "global_moderator" },
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->partialUpdateUsers([
 'id' => 'james_bond',
 'set' => [
  'role' => 'global_moderator',
 ],
])
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
response = client.update_user_partial(
 {"id": "james_bond", "set": {"role": "global_moderator"}}
)
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
var update =
  UserPartialUpdateRequestObject.builder()
    .id("james_bond")
    .setValue("role", "global_moderator")
    .build();

User.partialUpdate().user(update).request();
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var result = await client.Users.UpdatePartial(new UserPartialRequest
{
  ID = "james_bond",
  Set = new Dictionary<string, string>
  {
    { "role", "global_moderator" },
  }
});
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.update_user_partial({
 id: 'james_bond',
 set: { role: 'global_moderator' }
})
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
update := PartialUserUpdate{
	ID: "james_bond",
	Set: map[string]interface{}{
		"role": "global_moderator",
	},
}

resp, err := c.PartialUpdateUsers(ctx, []PartialUserUpdate{update})
```

</codetabs-item>

</codetabs>

---

This page was last updated at 2025-08-15T14:14:13.184Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/android/migrating_from_legacy/](https://getstream.io/chat/docs/android/migrating_from_legacy/).