# Discourse Dynamic Groups

**URL:** https://meta.discourse.org/t/discourse-dynamic-groups/365342
**Category:** Plugin
**Created:** [May 8, 2025, 4:18pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342 "2025-05-08T16:18:18Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [May 8, 2025, 4:18pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/1 "2025-05-08T16:18:18Z")

</div>

| | | |
| --- | --- | --- |
| ℹ | **Summary** | Automatically manage group membership |
| 🛠 | **Repository Link** | [https://github.com/communiteq/discourse-dynamic-groups](https://github.com/communiteq/discourse-dynamic-groups) |
| 📖 | **Install Guide** | [How to install plugins in Discourse](https://meta.discourse.org/t/install-plugins-in-discourse/19157) |

### Features

Discourse communities often need to automate group memberships based on conditions like badge ownership or existing group memberships.

Common use cases include:

- Users not in the ‘subscribers’ group

- Users not banned from posting in #Marketplace

- Users at TL0 or TL1, but not TL2

- Users who have completed the new user tutorial or have been members for over a year

- Users belonging to client\_1, client\_2, or client\_3 and are not an intern

Previously, solving this required custom scripts that periodically synchronized groups. The Dynamic Groups plugin eliminates that need.

This plugin introduces a boolean expression field to group settings, allowing administrators to define rules that dynamically determine group membership.

### Examples:

- users who are not in the ‘subscribers’ group  
`trust_level_0 AND NOT subscribers`

- users who are not banned from posting in #Marketplace  
`trust_level_2 AND NOT banned_users`

- users who are on TL0 or TL1 but not on TL2  
`trust_level_0 AND NOT trust_level_2`

- users who completed the new user tutorial or are member for over a year  
`badge:certified OR badge:anniversary`

- users who belong to client 1, 2 or 3 and are not an intern  
`(client_1 OR client_2 OR client_3) AND NOT interns`

### Configuration

Once the plugin is installed and enabled, a new tab will appear in the group admin interface:

 ![image](https://global.discourse-cdn.com/meta/original/4X/0/9/2/092cc8d128be1565a4a2b85d46959524f8fae66b.png)

When you enter or update the boolean expression, the system will take a few moments to populate the group with matching users. From that point on, group membership will be automatically updated as user status changes.

**Important:**  
When a rule is defined, the group is marked as **automatic** , disabling manual member changes. To revert the group to manual management, simply clear the expression field. The existing members will remain, and you’ll regain manual control.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [May 9, 2025, 10:39am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/2 "2025-05-09T10:39:00Z")

</div>

Wow! Awesome work, Richard!

This fills a large gap in group management within Discourse. Totally delighted, and looking forward to giving it a good run.

I’ll be primarily using it to enable functional subgroups.

---

<div class="post-metadata">

### Author: ![schneeland](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/schneeland/32/275391_2.png) [@schneeland](https://meta.discourse.org/u/schneeland)
#### Post date: [May 9, 2025, 2:48pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/3 "2025-05-09T14:48:54Z")

</div>

Definitely a welcome addition to Discourse’s features!

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [May 23, 2025, 7:47am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/5 "2025-05-23T07:47:47Z")

</div>

7 posts were merged into an existing topic: [Only the first entry working with Multiselect fields when `User first logged in` Trigger used](https://meta.discourse.org/t/only-the-first-entry-working-with-multiselect-fields-when-user-first-logged-in-trigger-used/362903/2)

---

<div class="post-metadata">

### Author: ![joo](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joo/32/334852_2.png) [@joo](https://meta.discourse.org/u/joo)
#### Post date: [June 4, 2025, 5:31pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/10 "2025-06-04T17:31:20Z")

</div>

Hi, thank you for developing this super useful plugin!

I’m currently using Discourse Dynamic Groups to automatically add all non-anonymous users to a special group. My boolean expression is:

NOT anonymous\_users  
Expected behavior:  
When a new user registers (who does not belong to the anonymous\_users group), they should be automatically added to this group, without any manual intervention.

Actual behavior:  
Newly registered users are not immediately added to the group. They only get added after I manually re-save the boolean expression in the group settings.  
This means the group is not updated automatically as users join, unless I trigger a manual sync.

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [June 4, 2025, 10:15pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/11 "2025-06-04T22:15:32Z")

</div>

Hmm… good catch. And I do agree that this should be expected behavior.

From a technical POV, the plugin will only reevaluate group membership on two different conditions:

1. When the boolean expression in the group settings is saved
2. If a user is added or removed for a group mentioned in the boolean expression.

When a new user registers, neither is the case.

Can you try to change the expression to `trust_level_0 AND NOT anonymous_users` and report back if that resolves the issue?

---

<div class="post-metadata">

### Author: ![joo](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joo/32/334852_2.png) [@joo](https://meta.discourse.org/u/joo)
#### Post date: [June 5, 2025, 2:50am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/12 "2025-06-05T02:50:56Z")

</div>

Hi,

When I try to use the expression

```plaintext
trust_level_0 AND NOT anonymous_users

```

I get the error:  
`Unknown keyword, group or badge: 'anonymous_users'`

If I change the group name to my actual group, for example:

```plaintext
trust_level_0 AND NOT interns

```

I still get:  
`Unknown keyword, group or badge: 'interns'`

I have double-checked and I am copying the group’s unique name directly from the group admin page, so there are no typos.  
Is there anything I might be missing, or is there something else I need to configure for custom groups to be recognized in the expression?

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [June 5, 2025, 9:32am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/13 "2025-06-05T09:32:36Z")

</div>

Thank you for reporting this.

While trying to reproduce, I have identified two bugs and one of them probably hit you.  
Can you please update the plugin to the latest version `59640f1` and see if that resolves the issue.

The plugin still does not deal with renaming groups very well. If you rename a group you should save the rules from all groups that depend on it (just enter a space after the boolean expression and remove it again to enable the Save button). This will be addressed in a later version.

---

<div class="post-metadata">

### Author: ![Heliosurge](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/heliosurge/32/571810_2.png) [@Heliosurge](https://meta.discourse.org/u/Heliosurge)
#### Post date: [June 20, 2025, 5:15am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/14 "2025-06-20T05:15:48Z")

</div>

> [@RGJ](#):
>
> Users not banned from posting in #Marketplace

Is this using your Category restrictor plugin or thi functions independently from it?

awesome plugin to fill in gaps.

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [June 20, 2025, 6:16am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/15 "2025-06-20T06:16:22Z")

</div>

> [@Heliosurge](#):
>
> Is this using your Category restrictor plugin or thi functions independently from it?

It functions independently.

---

<div class="post-metadata">

### Author: ![joo](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joo/32/334852_2.png) [@joo](https://meta.discourse.org/u/joo)
#### Post date: [August 5, 2025, 6:00am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/16 "2025-08-05T06:00:00Z")

</div>

Hi,

I am using the Dynamic Groups plugin and set my criteria as:

```plaintext
trust_level_0 AND NOT anon_group

```

However, I have noticed that users with trust\_level\_1 who are **not** in the `anon_group` are also being added to this dynamic group.

Could you please confirm if this is the expected behavior, or if this is a bug?

---

<div class="post-metadata">

### Author: ![Moin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/moin/32/554653_2.png) [@Moin](https://meta.discourse.org/u/Moin)
#### Post date: [August 5, 2025, 6:04am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/17 "2025-08-05T06:04:47Z")

</div>

Users with trust level 1 are also members of the trust level 0 group. So the behavior is expected. You could exclude the trust level 1 group to only get TL0 users. Similar to the example from the first post

> [@RGJ](#):
>
> users who are on TL0 or TL1 but not on TL2  
> `trust_level_0 AND NOT trust_level_2`

---

<div class="post-metadata">

### Author: ![joo](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/joo/32/334852_2.png) [@joo](https://meta.discourse.org/u/joo)
#### Post date: [August 5, 2025, 7:18am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/18 "2025-08-05T07:18:16Z")

</div>

Thank you for the clarification

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [April 27, 2026, 6:24am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/19 "2026-04-27T06:24:43Z")

</div>

I absolutely ❤ this plugin - it is just super helpful for several use-cases. Cudos again to the Communiteq team for sharing and maintaining it!

### UX thing - Would it be better to hide the key fields rather than the whole Membership tab?

I note that it hides the Membership tab of Group pages. I mean this one:

 ![image](https://global.discourse-cdn.com/meta/original/4X/a/b/4/ab43cce0d29a1fbc38b24eb0bef450d8fe62f3d8.png)

While I can understand why, this does cause some problems when you want to muck about with the Default title, Flair, and Effect.

This can be worked around by ~~either revealing the tab in the browser console, or~~ removing the expression in the Dynamic Groups tab, refreshing, making the changes, pasting it back again, and again refreshing.

But I do wonder if it might be better to just hide the fields that aren’t helpful instead, rather than the whole tab. Something more like this:

 ![image](https://global.discourse-cdn.com/meta/original/4X/f/b/e/fbea306e57a1ad273fd67d37ea69213debee46d0.png)

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [April 27, 2026, 7:25am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/20 "2026-04-27T07:25:20Z")

</div>

I do agree with your suggestion, but…

This is core functionality.  
A dynamic group is marked as “automatic” and then the Membership tab will disappear.

> [@nathank](#):
>
> This can be worked around by either revealing the tab in the browser console

That won’t work, since Discourse core won’t output the tab at all. It’s not hidden, it’s simply not there.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [April 27, 2026, 7:28am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/21 "2026-04-27T07:28:14Z")

</div>

Yeah, I worked that out in the time between posting and you replying!! I hadn’t appreciate that you hook into core functionality with it - slickly done too.

Have crossed out my incorrect suggestion.

I guess the other workaround I outlined is fine then.

It does raise another problem that I hadn’t realised - automatic groups are _NOT visible_ to non-staff users. And that is deeply coded in. Rats!

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [April 27, 2026, 10:15am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/22 "2026-04-27T10:15:42Z")

</div>

> [@nathank](#):
>
> It does raise another problem that I hadn’t realised - automatic groups are _NOT visible_ to non-staff users

I didn’t realize that either!

We’re going to do a maintenance round on all plugins in the next month or so, maybe we need to revisit the ‘automatic’ flag since as far as I recall it was just a quick way on disabling the add/remove members functionality. All other things are probably unwanted side effects.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [July 15, 2026, 12:29am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/23 "2026-07-15T00:29:48Z")

</div>

> [@RGJ](#):
>
> We’re going to do a maintenance round on all plugins in the next month or so, maybe we need to revisit the ‘automatic’ flag since as far as I recall it was just a quick way on disabling the add/remove members functionality.

Did you ever land on anything with this?

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [July 31, 2026, 2:20am UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/24 "2026-07-31T02:20:43Z")

</div>

There are a couple of deprecation notices on this plugin at the moment:

![image](https://global.discourse-cdn.com/meta/original/4X/7/b/c/7bc827ed32365ba5b7ad0de3dca8e0bbcd4d7651.png)

![image](https://global.discourse-cdn.com/meta/original/4X/1/9/5/1953e0852e47eda12026640fdb1db5d1df2877b5.png)

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [August 8, 2026, 2:12pm UTC](https://meta.discourse.org/t/discourse-dynamic-groups/365342/25 "2026-08-08T14:12:19Z")

</div>

> [@nathank](#):
>
> couple of deprecation notices

I have resolved them. Thanks for reporting these! 👍

[Next page](https://meta.discourse.org/t/discourse-dynamic-groups/365342.md?page=2)
