How-to › Document and support developers

How to choose a developer community platform for year one#

Score Discord, Discourse, GitHub Discussions, Slack, and Zulip on search, moderation, identity, cost, and export, then commit to one platform for a year.

Audience
DevRel
Level
beginner
Topic
Run developer relations
Verified

Your API has a few hundred users and no shared place to ask a question. Support arrives by email, in GitHub issues that are not bugs, and in replies under a release announcement. Each answer is written once, read once, and lost, so the same three questions come back every week and nobody outside the team can find last month’s reply.

What you get

You will end up with a scored comparison of six options and a weight set that states what your first year needs. One platform comes out on top, and you commit to it until a review date you set. This is for you if you run developer relations for an API or SDK and have no community platform yet.

Short answer

Score Discord, Discourse, GitHub Discussions, Slack, and Zulip on six things that decide a first year. Those are whether answers are readable without an account, moderation tooling, whether a developer can join with an account they already hold, cost, data export, and speed. Weight them for your situation, take the top score, and stay on it for the year. A forum wins on search and export, chat wins on speed, and launching on both splits the same thirty people.

You will need

Node 22 or later, and an API or SDK with at least one external user, because a community with no members is a decision with no evidence. Verified 2026-09-25 against Node 22.22.2. The scoring is a file and a script rather than a slide, so a colleague can dispute one cell and rerun it. Slack sits in the table because most teams already have it open, and its free plan hides messages after 90 days.1

Approaches compared

ApproachWhen it fitsWhat it costs youWhen to pick something else
DiscordUsers who want to talk in real time, voice included, and a team online most of the dayEvery answer is invisible to a search engine, so the same question is asked and answered again each monthSearch traffic matters more than presence, or nobody can moderate in the evenings
Discord plus Answer OverflowAn existing Discord whose help threads deserve to be foundA second service to run or pay for, and only threads in the channels you select reach the webYou have not launched anywhere yet, so a forum costs less than a bridge
DiscourseA small team that needs moderation to keep working while it sleepsHosting at 100 dollars a month or a server you run, and a slower conversation than chatYour users are on GitHub already and the questions are about the code
GitHub DiscussionsUsers who already hold a GitHub account and questions that live near the codeNo trust levels or limits on a new account, and an export that exists only through the GraphQL APIYour users are not on GitHub, or you may leave GitHub
SlackA private customer group where every member is invited by nameA separate account per workspace, and on the free plan messages leave view after 90 daysThe community is public, or answers must outlive a quarter
ZulipChat that must also be readable by the public, on a sponsored or self-hosted planWeb-public channels are off by default and tied to a plan, and the topic model takes explainingYour users expect Discord or a forum, and nobody will learn a third shape

Chat and forum are the two shapes, and the rest is detail. Discord gives the fastest conversation and the least searchable one. Discourse gives every thread a public page and trust levels that limit what a new account can do, at the cost of a hosting bill and a slower pace. GitHub Discussions gives the reader an account they already have and no way out other than the API. Answer Overflow narrows the gap for Discord without closing it.

Score what each platform can show a search engine

The inventory is a JSON file with one entry per platform and one score per criterion, on a scale from 0 to 3. Each score carries the reason and the page the reason was read from.

      "name": "Discourse",
      "scores": {
        "search": {
          "score": 3,
          "why": "A server-rendered crawler layout with structured data, and allow_index_in_robots_txt on by default",
          "source": "https://meta.discourse.org/t/how-public-discourse-sites-are-indexed-by-search-engines-like-google/1184"
        },
        "moderation": {
          "score": 3,
          "why": "Five trust levels that limit new accounts and promote regulars automatically, plus flags and staff roles",
          "source": "https://meta.discourse.org/t/trust-level-permissions-reference/224824"
        },

A score without a source is an opinion, and the validator refuses it. Two scores carry the argument. Discord scores 0 on search because its messages are read through the messages API by a client holding VIEW_CHANNEL and READ_MESSAGE_HISTORY, which a crawler does not hold. Discourse scores 3 because it detects a crawler by user agent and serves it a server-rendered layout with structured data.2 GitHub Discussions scores 3 for a plainer reason: a discussion inherits its repository’s visibility, so on a public repository it is a public page.

Moderation is where the forum earns its second point. Discourse ships five trust levels, and a new account cannot send messages, post attachments, or post more than two links until it has read enough to leave level 0.3 Discord’s AutoMod blocks keywords and spam and can make a new member wait ten minutes before posting. None of GitHub’s tools, which are lock, delete, convert, and block a user, limits an account that joined this morning.

Weight the criteria for the year you are in

The weights are the only opinion in the file, and they are written down so they can be argued with.

export const PROFILES = {
  'year one, a few hundred users, one part-time moderator': {
    search: 3, moderation: 2, identity: 2, cost: 1, export: 2, realtime: 1,
  },
  'launch week, chat first, search and export set aside': {
    search: 0, moderation: 1, identity: 1, cost: 1, export: 0, realtime: 3,
  },
}

Search carries 3 in year one because an answer nobody can find is an answer that gets written again, by you. Export carries 2 because the year ends with a review, and a review that cannot move the archive is a review with one possible outcome. Cost carries 1 because every option here has a free path for a few hundred people, so the money is not where the cost is.

node demo.mjs
year one, a few hundred users, one part-time moderator
  weights search 3, moderation 2, identity 2, cost 1, export 2, realtime 1
  1. Discourse                      28/33  85%
  2. GitHub Discussions             25/33  76%
  2. Zulip                          25/33  76%
  4. Discord plus Answer Overflow   19/33  58%
  5. Discord                        14/33  42%
  6. Slack                          13/33  39%
  Discourse over GitHub Discussions: export, worth 4 points
  Discourse over Zulip: search, worth 3 points

launch week, chat first, search and export set aside
  weights search 0, moderation 1, identity 1, cost 1, export 0, realtime 3
  1. Discord                        15/18  83%
  2. Discord plus Answer Overflow   14/18  78%
  3. Slack                          13/18  72%
  3. Zulip                          13/18  72%
  5. GitHub Discussions             11/18  61%
  6. Discourse                      10/18  56%
  Discord over Discord plus Answer Overflow: cost, worth 1 point
  Discord over Slack: cost, worth 1 point

Read the second line under each ranking before the first. Discourse and GitHub Discussions tie on search, and what separates them is export. A Discourse administrator downloads a full database backup that restores onto any other Discourse. A GitHub discussion leaves through the GraphQL API or not at all. Against Discord the gap is search, whose nine points are far more than any other criterion contributes.

The second profile is the launch week, with search and export set to zero, and Discord wins it. The order moved because the weights moved. Any scoring you are shown should be able to do that, and one that cannot has the weights hidden in the scores.

Count what a split costs

The pitfall is opening two platforms on the same day, so that nobody has to choose. Thirty people who answer questions become fifteen and fifteen, which leaves every question seen by half a crowd.

export function seenWithinAnHour({ active, p, platforms = 1 }) {
  if (!Number.isInteger(active) || active < 0) throw new Error(`active must be a whole number, got ${active}`)
  if (!(p >= 0 && p <= 1)) throw new Error(`p must be between 0 and 1, got ${p}`)
  if (!Number.isInteger(platforms) || platforms < 1) throw new Error(`platforms must be at least 1, got ${platforms}`)
  const perPlatform = Math.floor(active / platforms)
  return 1 - Math.pow(1 - p, perPlatform)
}
node split.mjs
30 active members, each looking in 13% of hours
  1 platform   30 people each  a question is seen within the hour 98% of the time
  2 platforms  15 people each  a question is seen within the hour 87% of the time
  3 platforms  10 people each  a question is seen within the hour 74% of the time

The model is a model: one look per member per hour, one in eight, independent of everything. It is not a measurement, but it is the right shape. The people are the scarce resource, the platform is not, and a second platform spends the people twice. The moderation load doubles in the same move, and the person who answers on both writes every answer twice.

Check it worked

Eleven tests pin the rules, and three matter. The year-one weights rank Discourse first and the launch weights rank Discord first, so the ranking is seen to follow the weights. Splitting thirty people across two platforms lowers the chance a question is seen within the hour. And a score with no source fails validation instead of ranking with a hole.

node --test score.test.mjs
1..11
# tests 11
# suites 0
# pass 11
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 114.243312

Rerun the tests after every edit to platforms.json. The literal Discourse in the year-one test is the line to read: if it stops matching, a score changed, and the reason for the change belongs in the cell beside it.

When it goes wrong

Every platform scores 3 on everything. The scores were written by the person who had already chosen. Require a source per cell, which the validator does, and have the person arguing for the losing platform write its row.

The ranking changes when a seventh criterion is added. The new criterion is carrying an opinion the weights were meant to carry. Keep the six, and change a weight instead, in the file, where the change is visible.

Discord wins in the meeting. The weights in the room were launch-week weights, and the year is not a launch week. Show both rankings, and ask which one the team will be living in by month nine.

The forum is quiet after the move. When thirty people were moved from a place with presence to a place without it, nobody told them what pace to expect. Publish an answer time, such as one working day, and meet it, because a forum runs on the expectation of a reply rather than the sight of one.

When not to do this

Do not run this scoring when the platform has been chosen for you. A partner’s Discord, a customer’s Slack Connect channel, and a company forum that already exists are constraints. The useful work is scoring what can be done about them, such as Answer Overflow on the Discord you were handed.

Do not launch on two platforms at once to avoid the decision. The split model is the whole argument, and it understates the cost, because the moderation load doubles and the same three people answer every question twice.

Do not put cost ahead of everything for a community of a few hundred people. Every option here has a free path, and the year of evenings you spend moderating is the cost the table cannot show.

Do not treat the year as a trial to abandon in the first quiet month. A defined year exists to stop the re-deciding, and a platform that is quiet in month two is quiet because it is month two. Set the review date on the day you launch, and score again on that date with the same file.

Last verified

Verified 2026-09-25 against Node 22.22.2. Every output block is what the command preceding it printed. Each score in the inventory was read from the platform’s own documentation on that date, and the page it came from is in the cell beside it. The weights and the split model are this page’s own rather than the result of measuring any platform in use.

Footnotes

  1. Slack’s usage limits page says a free workspace hides messages older than 90 days to make room for new ones, and deletes anything older than a year. The page does not say what the room is made of. A tip one paragraph earlier says that upgrading removes the limit, without adding any room. ↩︎ Back to text

  2. Discourse renders every public page twice. The indexing reference says a crawler, detected by its user agent, is served a separate server-rendered layout with DiscussionForumPosting markup and pagination links. A browser with JavaScript switched off gets a noscript copy of the same topic. The rendering built for machines is the one made of plain HTML. ↩︎ Back to text

  3. Discourse has five trust levels, numbered 0 to 4, and its own documentation has two names for the top one. The permissions reference lists level 4 as Inner Circle, and the detailed explanation lists it as Leader, reached by manual promotion only. Discourse’s 2018 post on the subject, as it reads today, adds that a site begins in bootstrap mode and grants level 1 to its first 50 accounts. The founders of a community never meet the limits they keep for everyone who arrives later. ↩︎ Back to text

Read this page as markdown · All how-to guides

Generate the client instead of writing it#

Retries, timeouts, pagination and auth are the same problems in every client. Voxgig generates them from your OpenAPI description, in 23 languages, from one model.

Get the Voxgig dispatch

Short notes on building SDKs, CLIs, REPLs, and MCPs for API-first teams, plus the occasional Fireside episode pick.

By signing up you agree to our Terms and Conditions.