Skip to main content
iVentureTeam

res_user_group_ids

res_user_group_ids is the widget behind the access rights grid on the user form. It generates a whole form view at runtime from a hierarchy the server sends, which is why it works nowhere else.

September 18, 2026Updated September 18, 20264 min read
Technical nameres_user_group_ids
Field typesmany2many (res.groups)
Viewsform
Moduleweb, present in every Odoo database
Used in core3 uses in Odoo 19, in odoo/addons/base/views/res_users_views.xml (twice, on group_ids) and res_groups_views.xml (once, on implied_ids). Same in Odoo 20.
VersionsOdoo 19.0, Odoo 20.0
No-code setupNo. This widget builds one specific screen and has nothing to configure.
Alternativesmany2many_tags, many2many_checkboxes, res_user_group_ids_privilege

What the res_user_group_ids widget does

Access rights in Odoo are a many2many to res.groups, but nobody wants to manage them as a list of group records. This widget turns that relation into the grid administrators actually use: application categories down the page, each with a dropdown choosing the level of access.

It does that by building a form view in the browser at runtime. It reads a structure the server sends alongside the record, view_group_hierarchy, containing the groups, the privileges and the categories, then generates selection and boolean fields for each and renders them through the standard form renderer.

The descriptor declares no options. There is nothing to pass it, because everything it draws comes from that server-sent hierarchy.

What this means for your team

This is the screen where somebody decides whether a new starter can see other people's salaries. It is worth understanding that what you are looking at is a presentation of the group membership underneath, not a separate permission model.

Two consequences matter in practice. Anything you set here ends up as plain group membership, so a module that adds groups will change what this screen offers without anyone touching a configuration. And the grid only shows what the server sent: if a group is missing from the hierarchy, it is not visible here even though it may still be applied to the user.

For an audit, read the underlying group membership rather than this screen alone.

Working examples

The standard use, on the user form:

<field name="group_ids" widget="res_user_group_ids" nolabel="1" colspan="2"/>

And on the groups form, for implied groups:

<field name="implied_ids" widget="res_user_group_ids" nolabel="1" colspan="2"/>

Putting it on any other many2many to res.groups will not work, because the record will not carry view_group_hierarchy.

Two categories on the screen that are not in the database

If you go looking for the Other and Extra Rights sections in your category data, you will not find them. The widget creates both during setup.

Other collects privileges that have no category, so they are not dropped off the screen:

const privilegesWithoutCategory = Object.values(privileges)
    .filter((privilege) => !privilege.category_id)
    .sort((privilege) => privilege.sequence);
if (privilegesWithoutCategory.length) {
    categories.push({ id: "other", name: _t("Other"), ... });
}

Extra Rights collects groups that belong to no privilege at all, and renders each as a checkbox rather than a dropdown:

this.extraCategory = {
    id: "extra",
    name: _t("Extra Rights"),
    privileges: Object.values(groups)
        .filter((group) => !group.privilege_id)
        ...
};

That split is the rule worth remembering. A group attached to a privilege becomes one option in a dropdown, where picking one deselects the others. A group with no privilege becomes an independent checkbox. So whether a permission is exclusive or additive is decided by whether its group has a privilege_id, not by anything on this screen.

If you add custom groups in a module and they show up as loose checkboxes under Extra Rights rather than as levels in your application's dropdown, that is the reason: they have no privilege, so the widget has nowhere else to put them.

Version compatibility

VersionStatusNotes
Odoo 19.0VerifiedVerified against the shipped 19.0 source.
Odoo 20.0VerifiedVerified against the 20.0 branch. No changes.

Unchanged between the two branches we checked, including its three usages.

What is changing in Odoo 20

No change. Diffing the registration between the 19.0 and 20.0 branches shows no options added or removed and no registration changes, and it is applied in the same three places in the base module.

The component is rewritten internally for OWL 3, as all of Odoo 20's widgets are, but the screen and its behavior are the same.

Common problems and fixes

SymptomCause and fix
The widget renders nothing or throws on another modelIt reads view_group_hierarchy from the record, and only res.users and res.groups provide it. Use it only on group_ids of res.users or implied_ids of res.groups.
Custom groups appear as loose checkboxes under Extra RightsThey have no privilege_id, so the widget puts them in the synthetic Extra Rights category. Attach the groups to a privilege if you want them to appear as levels in a dropdown.
A group applied to a user is not visible on this screenThe grid only renders what the server-sent hierarchy contains. Read group_ids directly to audit membership. Do not treat this screen as a complete list.
Selecting one level clears anotherGroups sharing a privilege render as one selection, so the options are mutually exclusive by design. Expected. Use privilege-less groups if the permissions should be additive.

Res_user_group_ids widget vs the alternatives

WidgetBest forKey difference
res_user_group_idsThe access rights grid on the user and group formsGenerates a form view at runtime from a server-sent hierarchy
many2many_tagsSeeing raw group membership for an auditLists the actual group records instead of summarizing them
many2many_checkboxesA flat list of groups with checkboxesNo categories, no privileges and no exclusivity
res_user_group_ids_privilegeOne privilege row inside this gridInternal to this widget and unusable on its own

There is no substitute widget, because nothing else understands the group hierarchy the server sends. If you need a simpler view of group membership for an audit or an export, read group_ids directly with a plain many2many_tags on a custom view, which shows the raw memberships this grid is summarizing.

Frequently asked questions

What is the res_user_group_ids widget in Odoo?+
It renders the access rights grid on the user form, turning the many2many to res.groups into categories of applications with a privilege selector each. It generates that form at runtime from the view_group_hierarchy value the server sends.
Why do some permissions appear as checkboxes instead of dropdowns?+
Because those groups have no privilege_id. The widget collects them into a synthetic Extra Rights category and renders each as an independent boolean, while groups that share a privilege become one mutually exclusive selection.
Can I use res_user_group_ids on my own many2many field?+
No. It reads view_group_hierarchy from the record, which only res.users and res.groups provide. On any other model there is no hierarchy to render.
Does it have options?+
No. The descriptor names a component and nothing else. Everything it draws comes from the server-sent hierarchy.

Not sure who can see what in your Odoo?

The access rights grid summarizes group membership rather than showing it, so an audit read off that screen can miss what is actually applied. We map real permissions per user, find the over-granted accounts and tighten them without breaking anyone's day.

Request an access rights audit

How this page was produced

Verified by reading addons/web/static/src/webclient/res_user_group_ids_field/res_user_group_ids_field.js on the 19.0 branch of a local clone of the official Odoo repository. The synthetic Other and Extra Rights categories are quoted from the component's setup. The registration was diffed against the 20.0 branch. Usage counts come from scanning every XML file in Community, Enterprise and odoo/addons/base, which is where all three uses live. Corrections welcome via our contact page.