How I built Fluxer, a Discord-like chat app

Fluxer is a free and open source instant messaging and VoIP chat app built for friends, groups, and communities.

Hampus Kraft
Hampus Kraft
January 24, 2026
How I built Fluxer, a Discord-like chat app

Updated 24 May 2026: since Discord's age-verification announcement, Fluxer now runs on a larger hosted deployment, has a small team, has started Visionary testing for native mobile, and has put self-hosting near the top of the roadmap. The Gateway was split from a monolithic cluster into six specialised tiers during a scheduled maintenance window on 24 May 2026.

Discord will require a face scan or ID for full access next month
Age verification for all.

I'm Hampus Kraft, a 23-year-old software developer from Sweden. I'm nearing completion of my BSc in Computer Engineering at KTH Royal Institute of Technology. You can find my LinkedIn page here.

In Sweden, our resident and company registration databases are public records. I'm an open book!

Ever since 2020, when the pandemic hit and I was still in senior high school, I've been fascinated by Discord, the instant messaging and VoIP chat app with over 200 million MAU that took the world by storm.

Fluxer is an OSS community chat app I worked on solo, on and off, for five years. It is one of the closest FOSS attempts at the kind of chat app people expect from Discord or Slack.

All of it is free and open source software (AGPLv3).

Fluxer in 60 seconds

Why use Fluxer when Discord is free and works well? And, realistically, why trust a new app that could disappear next week?

If Discord does what you need, and you're fine relying on a proprietary, investor-driven app that has reportedly filed confidential IPO paperwork, then you may not need Fluxer. I want to compete with Discord's network effect by building a real alternative.

Discord's IPO could happen in March | TechCrunch
Discord reportedly filed confidential IPO paperwork and has pinned its hopes on a debut in March.

Fluxer is for people who want different incentives: free, open source, self-hostable software, with an optional hosted version run by an independent, European-owned provider.

Fluxer matches the features and feel people expect from centralised proprietary platforms such as Discord or Slack.

Fluxer can succeed without Discord getting worse. It depends on giving technical users and communities a real alternative.

Discord's network effect is hard to beat head-on, so I'm focusing where switching is already plausible: technical users and communities that value control and transparency, and want software they can run on their own terms. Others may simply prefer a European-owned instance run without exploiting its users, with clearer incentives.

Fluxer is free and open source (AGPLv3), and the rule is simple: it's always the same software. The funding is built around giving people multiple ways to support Fluxer, depending on how they want to use it:

  • First, we run an official hosted freemium instance. It's free to use and it has a Plutonium subscription for users who want higher limits. We also offered a limited-time lifetime Visionary plan for early supporters. It sold out at around 1,000 copies before we stopped it!
  • Second, we accept donations from individuals and organisations who self-host Fluxer and still want to contribute to its development.
  • Third, for people who self-host and want help, we will offer prioritised support through a one-time Operator Pass. The price is $199 or €199, and it gives you direct help from the Fluxer team with deployment and day-to-day operations after the docs and setup guides are solid.
  • Managed hosting will come later. Right now, the priority is making self-hosting reliable first.

If the hosted free tier limits are too tight, you can always run your own instance. Fluxer will keep the software free of feature paywalls and licence key checks. It does not force upgrades to unlock quotas on software you run yourself. No SSO tax!

Now, my backstory

2017 to 2020

I first started using Discord in 2017, and my interest in it only grew over time. By January 2019, I had joined Discord Testers, their crowd-sourced bug reporting programme, and by April 2019 I'd earned enough XP to unlock the Bug Hunter badge. Around the same time, I was also accepted into Discord's HypeSquad Events programme, though I never got the chance to represent Discord at any events.

2020 to 2022

When the pandemic hit, I suddenly had a lot more time while studying from home to learn new things and improve my skills. Until then, programming wasn't something I took all that seriously, but the project I had in mind kept pulling me back.

During my senior high school years, I worked on early prototypes of what is now Fluxer. My final graduation project became that prototype, along with a technical report detailing what I'd learned from studying Discord's technical blog posts and architecture, and how I applied those ideas in practice.

When I graduated in summer 2022, I received a small $200 scholarship from the school, and the title "Web Guru of the Year."

2022 to 2023

I've been a student at KTH Royal Institute of Technology since autumn 2022. By summer 2023, I decided to focus more actively on Fluxer. However, my studies still took up much of my time, so progress was sporadic, with stretches of downtime.

In October 2022, I co-authored a medium-severity bug bounty report for a permission bypass vulnerability and submitted it to Discord's security team. The report earned my co-author and me a shared award of $1,500.

While I was studying, I ended up leading web development for a popular Minecraft: Bedrock Edition server with nearly 6 million registered players. I built and ran the web systems, working on API design, security, billing, and reliability.

It taught me how to keep large services running. I still help maintain those codebases when needed.

2023 to 2024

In July 2023, I released the first private alpha of Fluxer to a few dozen initial testers. Since then, I've iterated on the tech stack many times before settling on what I'm running today.

The current stack is heavily inspired by Discord and, to some extent, WhatsApp. It leans on battle-tested technologies like Cassandra (though self-hosters can use Postgres instead) and Erlang/OTP. I did try simpler alternatives because I wanted less complexity, but I kept running into the same problem: I'd end up reinventing the wheel for problems that proven technologies already solve well.

Those iterations, along with continued research into Discord's architecture, have paid off. I dug through Reddit and Hacker News posts from Discord employees, public Discord conversations with their engineers, and a lot of blog posts and postmortems. I also implemented ideas in practice to understand the tradeoffs. In parallel, I deepened my understanding of distributed systems both independently and through coursework.

My studies at KTH cover computer science and network security, plus software testing and distributed systems. That has helped me build a strong technical foundation.

My degree programme also emphasises applying and demonstrating knowledge in practice through projects. In spring 2024, I joined a project course where we delivered an internal tool for Giesecke+Devrient, an international security technology company.

2025

In January 2025, I grew wary of how Discord handled my personal data and where the app was headed. I built Discorch, a tool that guides you through Discord's undocumented privacy request process to bulk delete messages. It produces a CSV plus instructions for contacting Discord's privacy team to request deletion.

As more people used it, Discord kept changing the process and eventually imposed arbitrary limits, including blocking deletion of your own DM messages through this route because you can still delete those manually, so the route now only works for servers and groups you have left.

In spring 2025, I reported a security vulnerability to Discord that could have enabled unauthorised destructive actions against critical user-owned data without proper authentication, and I was awarded $2,000. Later that summer, I registered Fluxer Platform AB, a Swedish limited liability company, which required a minimum deposit of $2,000.

Maeby from Arrested Development: "Well, that was a freebie."

By summer 2025, I had finished most of my university courses and spent the whole summer writing my bachelor's thesis with a fellow student for the supportive and welcoming Intelligent Heart Technology Lab at KTH. The thesis was published in September 2025.

Between September and December 2025, I worked day and night to make Fluxer ready for public release. Getting the architecture, feature set, and web client ready for real users by myself was the hardest work I had done.

On 25 October 2025, I opened the first private beta because I needed some revenue to keep going. It was a small group of around 30 testers who could also invite people they knew, and a handful bought Visionary at $299 each while I kept working towards feature completion.

2026

That brings us to 2026. On 2 January 2026, I opened Fluxer up to everyone. I tried to do a Show HN, which did not go very far, and launched on Product Hunt, which gained a little more traction. A few more people bought Visionary, enough to keep me going, and I started polishing things up towards a self-hosting release.

There was effectively no marketing. Then a Bluesky post after Discord's IPO plans leaked started to travel further than expected, and Discord's age-verification announcement on 9 February 2026 changed the scale of the project overnight. It caught me by surprise: Fluxer grew to about 195,000 users, with a peak of around 11,000 concurrent connections, while the hosted setup was still built for a much smaller load and I was the only full-time engineer. In a real sense, 9 February 2026 is Fluxer's true birthday.

After Discord's age-verification announcement, Visionary sold out quickly: we sold around 1,000 copies at $299 each before pausing sales. Visionaries are recognised in-app with a numbered badge that shows how early they supported Fluxer.

I want to be clear that Visionary was never about FOMO. I had no idea what was coming. I capped it at 1,000 slots with an expiration date in October 2026 because that felt like a ceiling I would never come close to. I honestly expected to sell maybe a quarter of that by then at best, and even that would have felt really good. Selling out in a matter of days was the last thing I expected.

Fluxer feels familiar and has the features people expect from modern community chat. In a lot of areas it already does more than the other open source options, and it feels close to classic Discord.

The team is still tiny, but Fluxer is no longer just me trying to keep everything standing up alone. The goal remains the same: free and open source software under the AGPLv3, self-hosting without licence-key checks, and a hosted instance that answers to users.

You can support Fluxer through Plutonium, a custom donation, or future issues and PRs in the GitHub repo once the production work has been cleaned up for publication.

GitHub - fluxerapp/fluxer: A free and open source instant messaging and VoIP chat app built for friends, groups, and communities.
A free and open source instant messaging and VoIP chat app built for friends, groups, and communities. - fluxerapp/fluxer

Fluxer's backend (hello Mike!)

Discord's backend scaling work has been well documented, and the engineering team have been unusually open about how they build and operate it. Their posts have been a major reference point for me. Start here:

I've got a lot of respect for their engineers, but I'm less enthusiastic about some of Discord's business decisions. At the same time, a usable self-hosted alternative still doesn't really exist.

It takes an unreasonable amount of time and energy to build something good enough to replace what people already use. That can be demotivating, since people usually only pay once the app already feels close to what they expect.

What kept me going was a slightly obsessive desire to understand Discord's architecture in depth. That meant reading loads of HN and Reddit threads, digging through postmortems and blog posts, taking relevant courses at KTH as part of my degree programme, and building up professional experience along the way.

On top of that, I've been active in Discord's meta communities for years, regularly engaging with fellow Discord enthusiasts, security researchers, and bug hunters. I've spoken with Discord engineers directly on several occasions.

With that level of insight into Discord's development and the pain points people have with Discord, I am in an unusual position to use my know-how and build a serious alternative to proprietary community chat apps. That is what I want to do with Fluxer, and it is a lot more than a Discord clone.

What the backend looks like now

At launch, I described Fluxer as mostly TypeScript with a bit of Erlang. That was accurate enough then. Today the hosted Fluxer.app runtime is a set of services written in three languages, each picked for the kind of work it does. I am leaving out the public website and operations tooling here, since this section is about the chat app itself.

  • The HTTP API is a TypeScript monolith, running on Node with Hono. It owns most of what the app does: accounts, authentication, communities, channels, messages, attachments, billing, reports, downloads, unfurls, and the public HTTP API. Cassandra stores durable data, an in-memory store handles fast shared state, and NATS carries internal messages.
  • The Worker is also TypeScript. It runs work off the request path: attachment expiry, CDN purges, search and discovery refreshes, billing reconciliation, trust and safety list syncs, scheduled messages, data exports, and bulk message deletion. Jobs are queued through NATS JetStream, with a small cron scheduler enqueuing the periodic ones.
  • The Gateway is Erlang/OTP (plain Erlang on OTP 28, built with rebar3). It owns WebSocket connections, session management, event fanout, presence, guild routing, voice and call state, and push notification delivery. In production it is split into six specialised tiers: one stateless websocket tier that accepts connections, runs heartbeats, and relays frames, plus five stateful clusters for sessions, guilds, presence, calls, and push. Every node joins one distributed Erlang cluster, discovered through headless Kubernetes DNS, and rendezvous hashing routes each session and guild to an owner node, and then to a shard inside that node. The websocket tier holds no state, so it can be rolled at any time without disturbing live sessions or guilds.
  • The Media Proxy is Rust (axum on Tokio). It handles uploads, thumbnails, metadata, media transforms, external media, static files, and the upload relay. The heavy lifting runs through native libraries (libvips, libheif, and FFmpeg behind a hand-written C shim) wrapped in memory-safe Rust, with strict sanitisation (dimension and pixel-bomb limits, SVG scrubbing, aspect ratio and rotation handling), bounded concurrency, and request coalescing, so a hundred people opening the same image share one transform.
  • A fleet of small Rust data services sits behind the API, modelled on the data services Discord built between its API and its database. Each one fronts a hot access pattern (users, guilds, channels, members, auth sessions, read states, messages) with an in-memory cache and single-flight request coalescing, so a flood of identical requests for the same key collapses into one database hit. The same framework also runs a write-back in-memory key-value store that flushes to Cassandra, full-text search (an embedded Tantivy index), link unfurling, and a Snowflake ID generator that uses the same 2015 epoch and 64-bit layout as Discord's, so IDs sort by time the same way. They share one NATS-based RPC framework, with rendezvous-hashed shards that hand their in-memory state off to the next pod during a deploy. The monolith is being moved onto these services one read path at a time.
  • NATS and the in-memory store tie the services together. NATS carries API to service and API to Gateway RPC plus the background job stream, and the Gateway calls back into the API over HTTP to build your initial state when you connect. The in-memory store handles caching, rate limits, distributed locks, cache invalidation, pub/sub, and small operational queues.

The API and the Gateway own different halves of the system and call each other constantly. The API is the authority for accounts, permissions, billing, and app data. The Gateway is the authority for live sessions, routing, presence, and real-time delivery.

Repository note: GitHub is currently behind what runs on Fluxer.app. After the sudden growth, a lot of fixes had to land privately to keep the hosted service stable, covering scaling, reliability, abuse and safety, billing, and day-to-day tooling. Before publishing that code, we are splitting hosted-instance settings from reusable server code, removing details that only make sense on Fluxer.app, documenting the deployment settings, and making sure safety rules do not become a guide for bypassing them. The public repository will catch up with Docker images and self-hosting docs included.

A typical self-hosted deployment is much smaller than the hosted setup. The Kubernetes clustering and role-split tiers described above are specific to Fluxer.app. Self-hosting uses a lightweight setup with the API, Gateway, Worker, Media Proxy, database, an in-memory store, and NATS, backed by documented Docker images and a web-based setup flow. Small instances can run on a Raspberry Pi.

At launch, the Electron desktop app will support connecting to custom backends through in-app account switching. That means you can run your own instance and use it from the regular desktop client without waiting for full federation.

Why three languages?

A polyglot backend sounds like a maintenance tax, and it can be. It pays off here because the three languages line up with three very different kinds of work, and the boring majority of the app stays in just one of them.

Most of Fluxer is ordinary app code: accounts, permissions, billing, moderation, settings, REST endpoints. It is I/O-bound and it changes constantly, so what matters most is how fast one person can move through it. That work lives in TypeScript, end to end. The same language runs the API, the Worker, and the web and desktop clients, and they share types, validation, constants, and even a Discord-compatible Markdown parser (written in Rust, compiled to WebAssembly) across the wire. One person can follow a feature from a button in the client to the row in the database without switching mental models. For a codebase built mostly by one developer, that shared surface is the biggest reason I can keep moving fast on my own.

The real-time layer is a very different problem: hundreds of thousands of long-lived connections, each one needing isolation, supervision, and cheap concurrency. That is exactly what the Erlang/OTP runtime was built for, and trying to rebuild it in a general-purpose language is how you end up living Virding's First Rule (quoted below). Discord and WhatsApp both proved the model at a scale Fluxer will not reach for years.

The third kind of work is CPU-bound and sensitive to latency and memory: decoding untrusted media, and shielding Cassandra from read amplification. There, a garbage collector and an interpreter get in the way. Rust gives predictable memory, no GC pauses, safe concurrency, and a safe way to wrap the C media libraries. It is also the language Discord reached for when the BEAM VM's garbage collector struggled with large data structures.

So the rule is simple: keep the fast-moving majority in the language that lets me move fastest, and only pay for a specialised runtime where the work really needs one. That keeps a small team moving while leaving room to scale the parts that need it.

Why choose Erlang/OTP?

The Erlang runtime system is designed for distributed, fault-tolerant, soft real-time, highly available, non-stop applications, with the ability to use hot swapping to change code without stopping the system.

Hello Mike. Hello Joe. Hello Mike. Hello Robert. Hello Joe. Hello Mike. Hello Robert. Hello Mike. Hello. Looks like we fixed the bug!

It was originally developed as proprietary software at Ericsson, a Swedish telecom company, by Joe Armstrong (who wrote his PhD thesis at my university, KTH Royal Institute of Technology, in the year I was born), Robert Virding, and Mike Williams in 1986. It was released as FOSS in 1998, and is maintained by the OTP unit at Ericsson.

Notable uses of Erlang/OTP at a very large scale include WhatsApp, plus Discord via Elixir (which compiles to bytecode for the same BEAM virtual machine that Erlang runs on). WhatsApp is far larger than Discord. With more than 3 billion MAU globally, it is largely built on top of Erlang, and they got there with a famously small engineering team.

I tried several real-time architectures before accepting this rule:

"Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang."

Robert Virding, co-creator of Erlang

Fluxer's real-time system works roughly like this. It is heavily inspired by Discord and wire-compatible with enough of Discord's protocol to make porting existing Discord gateway bots easier:

  • When you connect to the stateless websocket tier, you're asked to identify yourself with your authentication token.
  • A "session manager" handles the payload. Rendezvous hashing decides which node on the sessions tier owns your session, and that node sends an authenticated HTTP request over the internal network to the API monolith's RPC endpoint to validate your token.
  • If you're correctly authenticated, the API constructs everything needed for your "ready" payload and initial client state, along with an array of all guild IDs you belong to. This reads from the database in parallel and hits caches when it can.
  • Your Session GenServer monitors your Presence GenServer and the Guild GenServers for the guilds you belong to. The Presence GenServer is the ingress point for direct user dispatches, so events fan out to your connected sessions only. Monitoring on both sides lets each process clean up when the other exits.
  • The Guild GenServer keeps an up-to-date cache of guild properties, members, channels, and roles from API dispatches. This lets it work out which sessions should receive an event scoped to a specific channel.
  • Each Session maintains an in-memory buffer of received events to allow replaying missed events without reconstructing your entire "ready" state from scratch if you briefly lose your network connection. WebSocket connections linked to a Session will periodically acknowledge received sequence numbers to truncate its in-memory buffer.
  • Messages that mention you are queued for mobile push notifications, and that queue is truncated as you read them. If you're away from your desktop and not currently active on mobile, Fluxer may send pending push notifications for messages you haven't yet read.
  • Fluxer avoids sending unnecessary member and presence updates to your client. Updates are lazy and incremental instead of full snapshots, and payloads are zstd-compressed. This is the same direction Discord went when they cut their WebSocket traffic by 40%.

A big guild's member list can hold hundreds of thousands of entries that change constantly, and your client only ever wants a small, sorted slice of it. Fluxer keeps that list in an in-memory ETS table backed by a skip-list ordered set, all in pure Erlang. Discord hit the same wall and dropped their sorted member list into a Rust NIF when the BEAM VM's garbage collector couldn't keep up with a structure that big. I could write one myself if it ever came to that, but the Erlang version handles it well and I would rather keep this hot path in a single language.

Once I've tested this architecture in practice with a larger number of real users, I'll write a series of blog posts explaining how it works and the challenges I ran into. But kudos to the engineering team at Discord for the inspiration!

Why choose Cassandra?

Cassandra is what the Fluxer.app instance uses in production. The self-hosted release is designed to use Postgres by default.

For a long time, ScyllaDB was my database of choice. Discord also migrated to it after running Cassandra. As of December 2024, though, ScyllaDB is no longer open source software, which is a deal-breaker for me.

Jake Gold @jacob.gold I completely understand @scylladb.com's challenge with maintaining an OSS/open core business model.

On the other hand, I'm not sure I would have chosen ScyllaDB for Bluesky PBC's infra if there wasn't an OSS version.

So this is unfortunate but I can't blame them for doing what they need to do.
Why We're Moving to a Source Available Licence - ScyllaDB ScyllaDB is moving to a source available licence. Learn why, directly from CEO and co-founder Dor Laor.

All databases suck. I like Cassandra and I despise it at the same time. I still use it because it fits Fluxer's write-heavy, event-driven design.

First, Cassandra makes it hard to be accidentally inefficient. You have to think upfront about how your data is modelled and queried, because inefficient queries are either impossible or very explicitly opt-in (hello, ALLOW FILTERING).

Second, Cassandra prioritises high write throughput, and Fluxer is built to keep reads low. Its eventual consistency is an acceptable tradeoff to get that write path. When you send a message, the database does very little: it validates your auth session (a read that is usually served from cache) and writes the message row. Permissions are answered by the Erlang Gateway over RPC, which keeps an in-memory cache of everything needed to compute permissions in a community (called a guild internally), so a permission check is a fast internal call instead of a query. Clients mostly read from the database when starting a new session to populate initial state. After that, everything stays in sync through the event dispatching system.

Third, operationally, Cassandra removes an entire class of problems I've struggled with in traditional RDBMS setups. Postgres can absolutely be made fast, but it also gives you more ways to shoot yourself in the foot: JOINs, tuning indexes, locking behaviour, and sometimes needing downtime for certain migrations. With Cassandra, schema changes are always zero-downtime and there are no locks. I like that!

Finally, Cassandra is a good fit for Fluxer's message rows. Unfurled links, file attachments, and similar metadata work well as embedded documents. Cassandra gives you rich types like sets and maps, along with user-defined types that can be nested, typed, and stored efficiently. That means a single document does not need extra table queries or untyped JSON blobs.

Building Fluxer's data model on an RDBMS generally felt more "icky" than using a NoSQL database. After weighing a variety of options for this use case, NoSQL is simply what I prefer.

You mentioned Postgres for self-hosted instances?

Yes. The query builder I wrote for Cassandra already produces a backend-neutral description of what each query does: the key, the action, and the columns. The same query code can run against Cassandra in production or against a plain single-table store elsewhere.

Because Cassandra behaves like a key-key-value (KKV) store (partition key + clustering key, where the clustering key identifies a specific row within a partition), I already had to design my tables and queries so that every lookup requires knowing the full key, or at least a sufficiently specific leading part of it for SELECT queries.

In Cassandra, secondary indexes are typically implemented at the application level using additional tables optimised for alternative access patterns. These are maintained on writes (via logged batches), with optional denormalisation depending on how important it is to skip an extra read to fetch the full primary row. Materialised views and native secondary indexes exist, but they come with caveats that can make them risky in production.

Given those constraints, Postgres can use a single key-value table without relying on its relational features. In practice, I treat Postgres as a blob store keyed by the same enforced keys as Cassandra, with efficient prefix range queries for listing and scans, reusing my custom Cassandra query builder.

I'm open to adding support for other databases too. With this abstraction in place, Fluxer can support many databases, as long as you're OK with it falling back to a single table of serialised blobs when it's not Cassandra.

Fluxer's frontend (have mercy!)

Fluxer's web app codebase is complex, and it still deserves care. The PWA has improved a lot in the canary version of the client, and it no longer feels like the rough first version from launch. To try the newest client work, use the canary desktop build at canary.fluxer.app/download or the canary web client at web.canary.fluxer.app.

Canary has fixed hundreds of bugs and adds major voice and video work: screen sharing with audio, text in voice, DM call fixes, a redesigned input and output device system, more mic processing controls, and DeepFilterNet3 noise suppression.

The web app has to handle the details people notice immediately: infinite scrolling, stable scroll position, bounded caches, jumping in time, state reconciliation, unread handling, and Discord-compatible Markdown. Those parts are tedious, but they are the difference between a familiar client and a toy.

As of 20 May 2026, the native iOS and Android app is being tested among Visionaries. It is built with Flutter, the cross-platform app framework. The next milestones are a Plutonium beta and then a public release. The mobile app code will be open source too once it is ready to publish.

Unlike Discord, Fluxer welcomes all kinds of client modifications: custom themes, non-malicious account automation, third-party clients, and anything else that tickles your fancy. It is all FOSS anyway, so you are welcome to upstream things if they align with the goals of the project. Just be sure to open an issue first to discuss it :)

Electron? Right to jail, right away

Fluxer currently uses Electron. I know, I know. I'm not too happy about it either. Tauri is not mature enough for what I need yet, and I ran into hurdles there that I did not have to deal with in Electron. In the spirit of choosing boring technology, Electron unfortunately wins. A lot of apps give Electron a bad name, but it doesn't have to be that way.

Tauri uses the system webview. That sounds great on paper, but it leaves the desktop app at the mercy of whatever runtime the OS happens to provide, with whatever bugs and quirks come with it. And when those bugs happen, you can't just ship a fix by updating your runtime, because the runtime is tied to OS updates.

I will reevaluate Tauri when there's a mature, supported option for shipping a consistent runtime with it, like CEF (cef-rs).

GitHub - tauri-apps/cef-rs
Contribute to tauri-apps/cef-rs development by creating an account on GitHub.

For most people, Electron is an acceptable choice. It gives Fluxer a consistent desktop runtime while still sharing the same client foundation as the web app. That is a practical tradeoff.

I believe in the web platform for this kind of application. It is mature, cross-platform, well understood, and good at building complex interfaces that need to run on many devices. It is also the platform I know best. That experience is part of why Fluxer could ship with a PWA from day one.

The first PWA had rough edges, especially on mobile, but it worked, and it has improved a lot since launch. You can see that work today in canary, and it will keep improving while the native Flutter app moves through Visionary testing, Plutonium beta, and public release.

The best mobile client is native, which is why the Flutter iOS and Android app comes first. Flutter can target desktop later, and that may become a better option than Electron down the line. Until then, the priority is simple: ship a reliable client that behaves consistently across web and desktop.

The LLMephant in the room

Fluxer came from about five years of work.

If you have used Fluxer and know the limits of LLMs, this should be obvious. Software this large only reaches this level of quality when a competent person keeps working on it over time. In Fluxer's case, that means years of on-and-off development, testing, reworking, and learning from real users. Most of Fluxer's core predates LLMs becoming a normal part of software development, and the architecture, data model, protocols, safety decisions, technical choices, and sense of what Fluxer should be are mine.

Many models were trained in ways I disagree with, and I dislike the direction most AI companies are taking. More recently I have preferred local open source models where they are good enough, because the tool exists either way and I use it on my own terms.

The closest way to describe it is as a second brain. When the codebase is large and the problem is subtle, it helps to have something that can sit with a crash log, a failing test, or a rough specification and help me think through where to look next. That can save time on the slow, repetitive parts of the work without changing who is responsible for the result.

The important part is that I stay in control. I decide the architecture, shape the specification, review the change, run the tests, and make sure it fits the surrounding system. If I cannot explain the change, I cannot ship it. Every change still has to preserve code quality, handle failure cases, and fit the app.

That is especially important because Fluxer is a real app with real-time delivery, media processing, billing, moderation, abuse prevention, and user safety concerns. LLMs can help me get through more work while the bar stays the same.

The clean commit history has a simpler explanation. The early work happened privately over more than three years, and I squashed it when Fluxer moved from closed development to public source. That is normal for a closed-to-open transition.

The contributor policy follows the same principle:

Understand every change in your PR. You should be able to explain what it does and why it is correct.

Keep AI-generated text out of bug reports, pull request descriptions, and GitHub comments, except for direct translation if English is not your native language.

If you use LLMs for coding help, disclose it. The contribution still needs to be understandable, reviewable, and tested well.

Contributors are welcome. As more people work on Fluxer, LLMs should become less important to day-to-day development.

With enough donations, Fluxer can offer bounties for specific work. My goal is to make Fluxer sustainable and community-developed.

Who is building Fluxer now?

Fluxer is no longer a one-person project, but the team is still small for something this big.

I am still the only person who has worked across the whole codebase from the beginning, and I still spend most of my time building the app, working on backend architecture and reliability, and dealing with whatever urgent production problem needs attention that day. That also means support, trust and safety, abuse prevention, billing, accounting, and internal tools have all spent time on my desk.

Around that, we now have someone helping with direction and safety: where Fluxer goes, report review, policy work, and safety tooling. We also have an infrastructure-focused engineer working on scaling, monitoring, CDN work, internal tooling, and voice server deployment. The native iOS and Android app has a paid contributor focused on mobile implementation, and a newer team member is helping take support and billing load off my plate.

That is better than January 2026, but it is still a small team for an app this large.

Frequently asked questions

What about the open web?

Chat apps have swallowed useful knowledge that used to live on the public web, then made it invisible to search engines, archives, and people who are not logged in.

Discord seeks to solve a problem that it created | TechCrunch
Conversations on Discord can be hard to follow. Discord SVP Peter Sellis proposes making forum-like features, or using AI summaries.

With LLMs, Sellis said, Discord could take a long, meandering conversation and turn it into "something that could be more sharable and syndicated across the web." However, he said that he and his team hadn't "seen a solution that we feel great about yet."

Fluxer does not agree with Discord's premise here. We do not think LLMs should be used to turn people's "meandering conversations" into syndicated material. If something should become public, it should happen because a person or community chose to publish it.

This feature uses the web itself. Fluxer brings back the good parts of the web as a publishing and sharing medium: public pages with stable URLs, server-rendered posts, clear titles, search indexing, pages that can be archived, RSS and Atom feeds, and links people can share anywhere. People's posts remain their posts.

That is opt-in for communities that benefit from publishing parts of their forum-style spaces to the open web: open source projects, developer communities, modding groups, creator communities, research groups, support forums, and any other space where public answers are meant to be searchable and useful later. Private chat stays private.

This looks a lot like Discord!

Yes, Fluxer looks familiar on purpose. Community chat has a shape people already understand: server list, channel list, message timeline, member list, composer, and voice controls. Discord did not invent that. It built on patterns that were already familiar from IRC, TeamSpeak, Slack, forums, game launchers, and older community tools.

Fluxer values a clear first screen over novelty. A Discord-like app needs to feel easy to understand for people coming from Discord. Familiarity makes switching less painful, keeps people's muscle memory intact, and lets Fluxer compete on the parts people actually care about: ownership, openness, privacy, performance, self-hosting, federation, safety, and incentives.

That is also how copyright is supposed to work. Copyright protects specific expression. It does not give anyone ownership of the general idea of putting servers, channels, messages, members, and voice controls in places people expect. In the US, 17 U.S.C. § 102(b) says copyright does not cover ideas, procedures, systems, or methods of operation. TRIPS Article 9(2) says the same thing internationally. EU software law says the ideas and principles behind interfaces are not protected by copyright, and the CJEU said in SAS Institute v World Programming that functionality is not expression. Nobody owns the basic pattern of a usable community chat interface.

A comparison image showing similar community chat layouts across older apps.
Source: Imgur, "Whenever someone says Discord's UI is revolutionary."

Changing the layout only because people might compare it to Discord makes the app worse while pretending that difference is the same thing as quality. Fluxer changes things where it actually improves the app. Forcing people to relearn where messages, channels, servers, and voice calls live just adds friction.

I've tried a bunch of different takes on the UX, and they always end up messy. Just look at contemporary attempts to recreate the Discord experience while prioritising novelty over usability, like Root. I've tried those alternatives, and so have many others I've spoken to, and we keep reaching the same conclusion: they are harder to use than they need to be.

Is Discord's UX perfect? Of course not. Parts of it have got worse over time. But the older Discord model is still one of the easiest ways for people to understand a modern community chat app. Most open source community chat options fail because they neither feel familiar enough to switch to nor complete enough to replace what people already use. The result is an app that may be principled, but still feels worse to most people.

Classic Discord also feels nostalgic for many of us longtime Discord users, from before they began redesigning the UI. Fluxer can improve the details while keeping a working mental model that people already understand.

Fluxer can and will diverge over time. It will grow beyond "classic Discord, but open source". As self-hosting, public web publishing, multi-backend support, federation, moderation tooling, voice and video, and client customisation mature, Fluxer becomes more clearly its own thing. The point is to start from something familiar, then diverge where Fluxer has a better answer.

That said, Fluxer lets you fully customise your client's look with custom CSS, and it'll continue to. More UI experiments are always appreciated!

Why the name Fluxer, and why Plutonium?

The simple answer is that Back to the Future is my favourite film series. That is the honest origin story.

In the film, the flux capacitor is the thing that makes time travel possible. The DeLorean needs to hit 88 mph and draw 1.21 gigawatts, first from a plutonium-powered reactor. Fluxer and Plutonium are both little nods to that. Yes, naming your subscription after fictional nuclear fuel is a bit silly. That is part of the fun.

There is a more literal meaning too. Flux means change, movement, fluctuation. Chat is constantly moving: new messages, new people, new context, old conversations becoming something else over time. A chat app is almost never in a fixed state.

That also explains the logo. The approximately-equal sign felt fitting because something in flux keeps changing from one moment to the next. It is recognisable, but always changing. I am more engineer than designer, so this is where I landed, but it has grown on us.

The slightly more dramatic reading is that the name hints toward finding a better timeline for community chat, preferably one where chat apps keep their soul while chasing an IPO.

How long did Fluxer take to build?

The first version started around 2020, while I was still in high school during the pandemic. It became my graduation project, then turned into a long-running side project tested by friends while I studied and worked on other things.

The final run-up to public release began after I finished my bachelor's thesis in summer 2025. The private beta opened in October 2025, and Fluxer was publicly released on 2 January 2026.

The launch was quiet at first. Then Discord IPO news and Discord's age-verification announcement on 9 February 2026 put Fluxer in front of far more people than I expected. The hosted instance grew to around 195,000 users, with a peak of about 11,000 concurrent connections, while the team was still basically me trying to keep up.

The team is larger now, but still small.

Why build a chat app at all?

Because I have cared about community chat for a long time. I have been deep in Discord's ecosystem since 2017: testing, reading engineering posts, following architecture discussions, reporting bugs, and talking to people who understand that world.

Fluxer started as a technical challenge, but it became more philosophical over time. I wanted a modern community chat app without one company controlling the app, data, network, and incentives. Self-hosters, technical communities, open source projects, and creators all need software they can trust, customise, and move away from.

I never wanted to be different for the sake of it. I wanted to preserve what people love about that kind of chat, make it free and open source, and build towards decentralisation so the future is no longer decided by one company.

I've built a Discord bot. Will it work on Fluxer?

Yesn't! Fluxer's HTTP API and WebSocket Gateway API are heavily inspired by Discord's and, in many cases, are directly wire compatible with it. That means you can reuse existing Discord libraries and abstractions in many languages.

For example, you can use the core libraries from discord.js directly. It's a bit more low level, but it will take you very far. The Fluxer API docs guide you through a quick start using this approach. Forking existing Discord libraries and modifying them slightly will also get you far. Or you could create your own community-maintained Fluxer SDK, and email me (hampus@fluxer.app) to get it featured in the docs (or submit a pull request in the GitHub repository).

Note: the current docs are pretty mediocre. Sorry about that. Brand new, complete API docs and self-hosting docs are coming soon as part of the public repository cleanup.

Slash commands and similar features are still coming. If you want this added, you can support Fluxer through Plutonium or donations.

Why do attachments expire?

Because storage costs money, and Fluxer has no venture capital funding.

Large media adds up quickly. If every image, video, and random file stayed forever, the hosted instance would become free cloud storage with a chat app attached. That breaks the economics of a bootstrapped app trying to stay independent.

Expiry is based on file size. Small files last much longer, with the smallest files lasting about three years, and files can be renewed a little when they are accessed. The exact behaviour is documented in how attachment expiry works.

This is partly a cost-control feature, but it is also a privacy feature. Most attachments have no reason to live forever. If you self-host Fluxer, the policy is yours to configure, including whether expiry is enabled and how much storage your instance should allow.

Will Fluxer become like Discord?

I cannot make a magic promise about the future, but Fluxer's structure is designed to make that less likely.

The hosted Fluxer.app instance needs to be sustainable, which is why Plutonium exists, but the software itself is AGPLv3 and intended to be self-hostable. The long-term plan includes self-hosting, data portability, multiple backends in one client, and federation. The important part is that you can leave if the official hosted instance makes a decision you dislike.

That is the point of building this as FOSS. Trust is easier when leaving is possible.

Why monetise Fluxer?

Because running a real-time chat service costs real money. Servers, storage, bandwidth, monitoring, safety tooling, payment processing, support, and people's time all have to be paid for somehow.

The real question is who the app has to answer to. Venture capital can make an app look free for a while, but it usually comes with pressure to grow faster, extract more, sell more, and eventually answer to investors before users.

Fluxer's approach is simpler: keep a generous free tier, charge for higher limits on the hosted instance, accept donations from people who want to support the project, and keep self-hosting free.

Is Fluxer free and open source?

Yes. Fluxer is free and open source software under AGPLv3. The public repository is github.com/fluxerapp/fluxer, and the hosted Fluxer.app service and the self-hostable release are meant to be the same core software, with important features kept in the open.

Right now, GitHub is behind the code running on Fluxer.app. During the growth spike, urgent work had to happen privately so the hosted service could stay up. It touched scaling and reliability, abuse and safety, billing, and the tooling we run day to day.

That work needs cleanup before it is published. Some of it assumes Fluxer.app's production environment, and some of it contains hosted-instance safety rules that would be useful to spammers if copied out as-is. We are turning Fluxer.app-only settings into documented instance settings, removing private deployment details, writing the missing setup docs, and keeping the abuse protections useful without handing attackers a checklist.

Pull requests will reopen once the cleaned-up work lands in the public repository. Self-hosting documentation, Docker images, setup guides, and operator documentation are included in that public release.

Will self-hosting cost money?

No. Running your own Fluxer instance will require no licence key, paid tier, or special enterprise unlock. You will be responsible for your own servers, uptime, moderation, safety, and legal obligations, but the software itself is free to run.

The Operator Pass is a $199 or €199 one-time purchase for prioritised self-hosting support from the Fluxer team when community support or GitHub threads are too slow. It comes after the docs and setup guides are solid, and those stay public.

Federation?

Federation remains a major goal, and the order matters. People who run and use Matrix tend to complain about specific things: large federated rooms can be slow and expensive to join, presence and device-list updates can create a surprising amount of background load, federation failures can leave rooms or encrypted messages half-working, and moderation gets harder when abuse, media, bans, and bridges cross server boundaries.

The self-hosting release starts with account switching for custom backends in the Electron desktop app. Shortly after that, the client gets simultaneous connections to multiple backends without making you visually switch between workspaces. The goal is one client that can show several instances together before Fluxer has the unified identity and authentication model that full federation needs.

True federation can come after that, with OAuth2-based authentication against remote instances and a clearer model for where identity and data live.

How does moderation work?

Each Fluxer instance is responsible for its own moderation. Fluxer Platform AB operates the hosted Fluxer.app instance, so we are responsible for reports, safety enforcement, legal compliance, and abuse prevention there.

That is one reason GitHub is behind the hosted service right now. The code includes moderation, abuse-prevention, and operator tooling that still needs to be separated from Fluxer.app-specific settings. We need to publish them in a form operators can actually use, without making the hosted instance easier to attack.

We are also a registered ESP with access to the CyberTipline Reporting API from the National Center for Missing & Exploited Children (NCMEC).

Once federation exists, moderation still stays local to the instance enforcing it. A ban on one instance stays local unless other operators choose to share or honour that signal.

Why do you follow local laws in my country or state?

For self-hosted instances, this is ultimately the operator's responsibility. If you run Fluxer yourself, you decide where you provide service and what legal risk you are willing to accept.

For the hosted Fluxer.app instance, we do have to comply with the law where we serve traffic. Some recent age-verification laws are invasive enough that we restrict access instead of collecting government IDs or biometric data from everyone.

As of 24 May 2026, Fluxer restricts NSFW access in the United Kingdom and Brazil. In the UK, we can offer a less invasive optional adult check through a $0.00 credit card authorisation. Brazil currently lacks a privacy-preserving path we are comfortable with. Mississippi is stricter: it requires age verification for access to the whole service, so the hosted Fluxer.app instance blocks access from Mississippi instead.

The current details are kept in regional restrictions and minimum age requirements.

Where does Fluxer run?

The main hosted infrastructure currently runs in US East on Vultr. That location gives us good connectivity to both North America and Europe, which helps message loading and real-time delivery.

We are still paying attention to the geopolitical issues. The US CLOUD Act and broader data-sovereignty concerns are real. Longer term, federation makes it possible to partition accounts and communities by region, including EU-only hosting. Moving more infrastructure to Europe remains an option.

Voice and video are already more distributed. Current RTC regions include Sydney, São Paulo, Santiago, Frankfurt, Stockholm, Warsaw, Madrid, Mumbai, Singapore, Seoul, Johannesburg, Newark, Atlanta, Dallas, Seattle, and Los Angeles.

What happens when Google kills Tenor?

Fluxer currently relies on Tenor for GIF search in the app.

Google is killing the current Tenor API on 30 June 2026. Fluxer already has KLIPY support in the codebase, alongside Tenor. KLIPY was built by former Tenor people and is the most natural replacement for GIF search when the current Tenor API stops working.

We are not switching to GIPHY. Sorry, but not sorry.

GIFs are also proxied through Fluxer, so the user-facing privacy model stays the same: providers do not see your IP address just because you searched for or viewed a GIF through the app.

End-to-end encryption?

Platforms like Matrix do offer E2EE, but the complexity of the protocol and its client implementations often comes at the expense of what people actually want.

Why We Abandoned Matrix (2024) | Hacker News

Most people want a reliable, feature-complete, non-E2EE Discord alternative: fast clients, good search, profiles and statuses, custom emoji, straightforward roles and permissions, solid voice and video, and practical moderation tools that work.

That is where Fluxer's priorities lie. Adding E2EE to text messaging significantly increases complexity, and Fluxer is focusing first on building a stable community chat app that feels as capable as Discord.

Text on Fluxer has no end-to-end encryption today. Optional E2EE is still planned for the places where the tradeoffs make sense: personal notes, calendar data, DMs, and small groups. E2EE for large communities is out of scope.

Voice is already further along. Canary uses LiveKit's built-in E2EE support for voice and video in enrolled testing communities today. It rolls out to everyone soon, then becomes enforced as supported clients catch up.

Native mobile app?

Yes. The native app is built with Flutter for iOS and Android, and as of 20 May 2026 it is already in testing with Visionaries.

The rollout is staged: Visionaries first, then a Plutonium beta, then a public release.

The Flutter app can also target desktop later, making it an alternative to Electron. For now, iOS and Android come first.

The canary PWA has improved in the meantime. To use the newest client work before stable, try canary.fluxer.app/download or web.canary.fluxer.app.

Can I help localise Fluxer?

Yes. Fluxer already supports 34 locales across the app, email templates, marketing site, and similar places.

That currently means:

  • العربية
  • Български
  • 简体中文
  • 繁體中文
  • Hrvatski
  • Čeština
  • Dansk
  • Nederlands
  • English (United Kingdom)
  • English (United States)
  • Suomi
  • Français
  • Deutsch
  • Ελληνικά
  • עברית
  • हिन्दी
  • Magyar
  • Bahasa Indonesia
  • Italiano
  • 日本語
  • 한국어
  • Lietuvių
  • Norsk
  • Polski
  • Português (Brasil)
  • Română
  • Русский
  • Español (Latinoamérica)
  • Español (España)
  • Svenska (Sverige)
  • ไทย
  • Türkçe
  • Українська
  • Tiếng Việt

We care about localisation a lot. Pretending everyone can just use English is narrow-minded, and Fluxer needs to feel usable internationally whether English is your first language or not.

Right now, many translations are drafted and kept up to date with LLM help because the app changes quickly and the team is small. LLM literally means large language model, and this is one place where the tool is not half-bad: drafting the app's copy across languages. It saves humans from starting every locale from a blank page.

That first pass only gets us started. It helps non-English speakers get a better app sooner, and native speakers catch the things a model can miss: tone, terminology, awkward phrasing, and cultural details. People have already told us the current localisation is good in many languages, which is great to hear, but we still want speakers of those languages involved before we treat it as something people can rely on.

The next step is a self-hosted Weblate instance where localisation work can happen in the open. If you want to improve an existing locale or add a new one, email i18n@fluxer.app and we'll put you on the waitlist.

Do you have a Contributor Licence Agreement?

No. Fluxer had a CLA early on, mostly because the expected path at the time looked more like self-hosting support and companies running Fluxer themselves. A CLA would have made it easier to offer a separate commercial licence to organisations whose policies prohibit AGPLv3 software.

After Fluxer took off as a hosted app for regular users, that tradeoff stopped making sense. The CLA is going away when pull requests reopen with the cleaned-up codebase.

Where's the roadmap?

Roadmap 2026
The current 2026 roadmap for Fluxer: canary, mobile, self-hosting, localisation, federation, voice and video, and the backend reliability work behind it.
Where we're going, we need a roadmap.

Closing thoughts

If you care about this too, the best ways to help are code contributions, one-off or recurring donations, or a note to @fluxer.app on Bluesky.

I want Fluxer to stay fully independent and bootstrapped. That means relying on donations, whether one-off or recurring, along with revenue from early supporters and Plutonium on the hosted instance.

Got questions or concerns, or want to work with Fluxer? You can reach me directly at hampus@fluxer.app if you're a content creator, run an open source project, manage a community of any size, or work at a CDN or trust and safety vendor. If you're a fellow independent, bootstrapped, privacy-first alternative to the mainstream, or you're in the press, I'd love to talk too.

Fluxer has come a long way already. With your help, it can become a serious FOSS alternative to Discord.

See you in the Fluxerverse!

A DeLorean time machine lifts off, heading for new adventures.