How "difficult" is modifying/extending Discourse for a backend dev


I am an MLE who has some backend experience. My frontend skills are non-existent/pretty weak.

I am interested in hosting a small forum which requires the following features:

  • Filter posts by multiple tags in an easy way
  • Certain categories being hidden unless user is logged in
  • Sign ups needing to be admin approved
  • Photo carousel at the top of the site potentially

Is this type of stuff difficult to do? I’ve been looking at the code of some plugins and while the actual implementation is quite short and simple to read it looks difficult to write.


I’m in the same boat as you. I’ve got experience with nodejs backend. I have done a little bit of html/css/javascript on the front end too but I’ve done way more backend. There is a lot of what appears to be specialized code specific to discourse or ruby or a very opinionated coding style, even though I know javascript, the discourse code base looks intimidating and complex to me. I’m thinking strongly of trying to run my own local a.i. that I can feed the whole code base into and then ask it questions for things I want to do. Other than that, all I can do is read existing code, plugins, etc and try to make the best sense of it that I can. If you’re interested in sharing knowledge or trying to learn together, I’m open to it :slight_smile:

1 Like

Yes, there is quite a large learning curve. But all the things you mention already exist and no coding will be needed.

are in core Discourse, and

can be done with existing theme components.


I would KILL for some video courses on discourse development on Udemy. Just tell me who to throw money at. :dollar::dollar::dollar:


No need to tinker for this, it’s already supported by the API. And you can do this already from the front end! I created a “widget” (Glimmer Component!) just to do that!:

This component works in Right Sidebar Blocks & Layouts.

1 Like

Could this be used to create a nested hiearchy.

The forum I’m considering caters to older people who haven’t seen discourse like forums before.

Would be nice for them to still be able to navigate nested structures like traditional forums.

1 Like

For nesting use Categories.


Many Discourse instances opt into this, see:


Off topic, but this was so handy here, I love our explain using ai feature

an MLE in the given context refers to a Machine Learning Engineer. This is a professional who specializes in using data and algorithms to build models that enable machines to perform tasks without being explicitly programmed for those specific tasks. They generally have a strong background in computer science, statistics, and programming, and their expertise tends to focus on the backend aspects of technology, such as building and deploying predictive models and other machine learning products. When the original poster mentions “an MLE,” they are identifying themselves as a Machine Learning Engineer who is familiar with backend development but who lacks experience in frontend development.


A few thoughts about this.

Developing paid Discourse courses

The idea of courses related to Discourse development on a platform like Udemy or Coursera is interesting. I suspect the main issues are that there aren’t that many people outside of the Discourse team who would be qualified to create a course in Discourse development and that the potential number of students for a course is quite small. That said, I’m sure that a good course related to developing Discourse themes or plugins could get enough students over time to make it worth the effort of creating a course.

There’s also a possible issue that charging for Discourse courses might go against the spirit of this forum. I’m just speculating about that though.

Discourse development tutorials

I think the observation that the actual implementation of many Discourse plugins, themes, and theme components is quite simple is correct. As with developing for other platforms, the problem is getting past the initial barrier of not understanding how the parts fit together. The Discourse team (or some other qualified developers) could help with this by writing a few tutorials that walk you through the entire process of creating functional themes, theme component, and plugins. For example, a step by step guide to creating something like the Discourse Placeholder theme component.

I realize that this would require a large investment of time, so it would need to align with Discourse’s business goals.

Currently available resources

With a bit of searching, there’s lots of good information about Discourse development on this forum. Looking at code examples from the Discourse GitHub repo is also a great way to learn.

A recent tool that shouldn’t be ignored is GitHub Copilot. If you structure your development environment in the right way, it can be helpful for getting a sense of how to develop Discourse themes and plugins. For developing Discourse themes, the best approach I’ve found is to develop the theme (using the Discourse Theme CLI) in the root directory of my local Discourse installation. Structuring things this way gives Copilot easy access to the Discourse code base. (Note that for plugin development, the plugins folder is already in the root /discourse directory.) (Also note, I could be wrong about Copilot actually accessing the Discourse code base that I’ve loaded in my IDE. In any case, it’s helpful to have the core Discourse code available for my own reference.)

To avoid distraction and also to focus on using Copilot as a tool for learning, I turn off Copilot Completions in my IDE (VS Code) and just interact with Copilot via chat. Here’s an example of the kind of assistance it can give. (shopify.js is the file that was created by the Theme CLI in my theme’s /javascripts/discourse/api-initializers/ directory.)

Conversation with Copilot

scossar: Can you explain what the default export in shopify.js is doing? It’s essentially the boiler plate code that is supplied by Discourse when a theme is created with the discourse_theme gem. I’ve altered the boiler plate code so that it logs each page change. I understand the call to api.onPageChange, but I don’t have a clear understanding of how the api object is being injected into my code.

GitHub Copilot: The api object is injected into your code through the withPluginApi function that is called in the initialize method of the object returned by apiInitializer.

Here’s a simplified version of what’s happening:

  1. When Discourse starts, it runs all the initializers.

  2. The apiInitializer function creates an initializer that runs after the "inject-objects" initializer.

  3. When this initializer runs, it calls the withPluginApi function, passing in the version, cb, and opts parameters.

  4. The withPluginApi function checks if the current version of Discourse is compatible with the version specified. If it is, it calls the callback function (cb) and passes the PluginApi instance as an argument. This PluginApi instance is the api object you see in your code.

So, the api object is an instance of PluginApi, and it’s being passed to your code by the withPluginApi function. This object provides a number of methods that allow you to interact with Discourse, such as onPageChange, which you’re already using.

scossar: So the function that’s the second argument to the default export in shopify.js is the callback function that’s accepted by apiInitializer?

GitHub Copilot: Yes, that’s correct. The second argument to apiInitializer is a callback function. This function is called with the PluginApi instance as an argument when the initializer runs (assuming the current Discourse version is compatible with the version specified). This is how the api object is made available in your shopify.js file.

Once I’d sorted that out…

scossar: …One other thought, could api.decorateCooked be used to inject a ratings iframe that was hosted on an external application (for example, hosted by the Shopify app that I’m developing)?

GitHub Copilot: Yes, you can use api.decorateCooked to inject an iframe into a post. Here’s a rough example of how you might do this:

api.decorateCooked($elem => {
  const postId = $'post-id');
  const iframe = document.createElement('iframe');
  iframe.src = `${postId}`;
  iframe.width = '100%';
  iframe.height = '200'; // adjust as needed
}, { id: 'rating-iframe' });

In this example, api.decorateCooked is used to append an iframe to each post. The iframe’s source is set to a URL on your external application, with the post ID included as a query parameter. You would replace '' with the actual URL of your ratings page.

Please note that this is a simplified example. You might need to adjust it to fit your needs, and you should definitely add error handling and other necessary precautions to ensure it works correctly and securely.

It’s not reasonable at this point to expect Copilot to actually write all of your code, but it’s a great tool for learning how to write Discourse code.

I would think that having fewer categories and less hierarchy would be easier for old people.

Unless you have lots of traffic that is of interest to very few people you likely don’t need lots of categories.