Fjord

Behind the scenes at Fjord

What powers Fjord.

A bot in Rust. Our own graphics engine. Plus the frameworks, libraries and databases Fjord is built on.

Here we show what we develop ourselves and which technologies come together in Fjord.

01 The botFjord preserves event order within each server while processing independent work in parallel.

Fjord

Processing events in order.

Fjord processes Discord events in order and runs independent tasks in parallel. Twilight connects the bot to Discord and keeps server data available locally. Dragonfly stores pending events and supports coordination of gateway connections.

01

READY as a state boundary.

A new READY waits for earlier event tasks before Fjord replaces the server snapshot. Later events start only afterward, so old work cannot overwrite the new state.

02

FIFO per server.

Events from the same server start in arrival order. Each waits for the preceding task to finish, so changes to that server cannot overtake one another.

03

Parallel across servers.

The dispatcher separates tasks by key. Different servers can run at the same time; only tasks with the same key wait for one another.

04

One event, the right tasks.

The same message reaches AutoMod and the activity log at once. Each handles it separately for its own task.

05

Temporary data in Dragonfly.

Pending Discord events and their data are stored in Dragonfly. AutoMod and activity logs also use this shared store for temporary state. The bot still controls task execution.

06

One match, one response.

When an enabled AutoMod filter matches, checking that message stops. Other filters do not trigger a second moderation response for the same event.

07

Server data with Twilight.

Twilight keeps servers, members, roles, channels, emojis, presences and voice states up to date in memory. Messages are not part of this cache.

08

Interactions run separately.

Interactions are scheduled independently of server events. READY forms a state boundary within each gateway connection.

09

Shard ownership.

Dragonfly coordinates ownership of individual shards, or gateway connections. After a takeover, the former owner cannot claim or complete further events.

02 Fjell graphics engineImage processing in Rust, SIMD and measured performance.

01 / Our own development

Our images carry our signature.

Fjell is our own graphics engine written in Rust. It combines backgrounds, avatars and text into personal welcome cards.

We wanted control over how these images are created. So we developed a solution tailored to Fjord that gives us creative freedom.

Cost efficiency matters just as much. Fjell delivers maximum performance without sacrificing quality while keeping CPU and memory use during generation as efficient as possible. This drastically reduces our server costs.

Our implementation reaches down to pixel processing. Custom SIMD loops use AVX2, FMA and BMI1/BMI2 to calculate multiple pixels in parallel.

Preview of Fjord’s card editor with a designed welcome card
Designed in Fjord. Rendered with Fjell.

Performance measurement

Controlled benchmark*

Four load levels with controlled card variations and the same test setup.

ParallelCards/sCards/minRender avg.Render P50Render P95Render P99Total avg.Total P50Total P95Total P99CPU avg.RAM avg.
1797,4847.8491,062 ms1,061 ms1,226 ms1,242 ms1,253 ms1,251 ms1,428 ms1,473 ms88,3 %381,2 MiB
21.577,9594.6771,038 ms1,004 ms1,225 ms1,421 ms1,266 ms1,236 ms1,470 ms1,715 ms173,5 %360,1 MiB
43.173,00190.3801,023 ms1,011 ms1,188 ms1,230 ms1,259 ms1,243 ms1,448 ms1,557 ms344,9 %375,3 MiB
85.850,25351.0151,050 ms1,026 ms1,194 ms1,290 ms1,366 ms1,349 ms1,578 ms1,803 ms647,0 %385,8 MiB

Throughput scaling

Measured throughput compared with perfect linear scaling.

MeasuredIdeal linear
1248Parallel workersCards/s
WorkersMeasuredIdeal linearScalingEfficiency
1797,48797,481,00×100,0 %
21.577,951.594,961,98×98,9 %
43.173,003.189,923,98×99,5 %
85.850,256.379,847,34×91,7 %

All four local tests ran for 60 seconds each on an AMD Ryzen 9 9950X. They used 100 lightweight backgrounds with ordinary colours or illustrations and file sizes of about 100 to 300 KB, typically around 200 KB. The liquid layer remained disabled and the font stayed fixed; text and circle colours and their shader positions varied between cards.

Render time includes image generation plus PNG encoding and compression through completion of the final PNG. Network transfer and download time are not included.

The load generator used 1, 2, 4 or 8 parallel requests depending on the run. A new request began only after the previous PNG had been received completely and validated. The reported server CPU usage resulted under precisely this load. The graphics engine could distribute its server-side work across multiple cores.

* Internal measurements under the described conditions; not independently verified. They do not constitute a warranted characteristic, guarantee or performance commitment. Actual performance may vary by system, load and environment.

Aggressive random test

Benchmark with random cards*

A much more variable setup with 1,000 backgrounds, 237 fonts and random effects for every request.

ParallelCards/sCards/minRender avg.Render P50Render P95Render P99Total avg.Total P50Total P95Total P99CPU avg.RAM avg.
192,655.5599,775 ms10,478 ms12,781 ms13,401 ms10,788 ms11,553 ms14,006 ms14,784 ms93,6 %1.205,6 MiB
2184,5311.0729,944 ms10,621 ms12,858 ms13,550 ms10,832 ms11,576 ms13,938 ms14,698 ms189,1 %1.278,8 MiB
4358,8221.52910,209 ms10,855 ms13,240 ms13,997 ms11,138 ms11,857 ms14,363 ms15,212 ms377,7 %1.300,9 MiB
8660,5239.63110,897 ms11,610 ms14,343 ms15,336 ms12,101 ms12,889 ms15,838 ms16,880 ms744,8 %1.308,6 MiB

Throughput scaling

Measured throughput compared with perfect linear scaling.

MeasuredIdeal linear
1248Parallel workersCards/s
WorkersMeasuredIdeal linearScalingEfficiency
192,6592,651,00×100,0 %
2184,53185,301,99×99,6 %
4358,82370,603,87×96,8 %
8660,52741,207,13×89,1 %

These four local tests ran for 60 seconds each on the same AMD Ryzen 9 9950X. Every request selected from 1,000 more demanding backgrounds sized from 800 KB to 2.4 MB and from 237 fonts. Text, transparency, font and avatar sizes, outline, text and circle colours, and shader angle, strength and intensity were varied. About half of the cards also enabled the liquid layer with random colour, opacity and blur.

The load generator used 1, 2, 4 or 8 parallel workers in a closed loop. Each worker started its next request only after the previous PNG had been received completely and validated. Every 60-second run completed without errors, timeouts or invalid PNGs.

Render time includes image generation plus PNG encoding and compression through completion of the final PNG. Network transfer and download time are not included.

* Internal measurements under the described conditions; not independently verified. They do not constitute a warranted characteristic, guarantee or performance commitment. Actual performance may vary by system, load and environment.

03 Technology stackLanguages, frameworks, libraries, databases and object storage.

02 / Our technical foundation

What we build with.

Alongside our own engine, we use Rust, Leptos, TypeScript, Vue, Twilight, Dragonfly, PostgreSQL, ScyllaDB and RustFS. Each technology has a clear role in the system.

Programming language

Rust

Rust

Rust powers our Discord bot, backend, card editor and Fjell graphics engine.

Logo © Rust Foundation. CC BY 4.0 · unmodified

Web framework

Leptos

Leptos

We use Leptos for parts of our web interface. The framework brings Rust to the browser and fits naturally into the rest of our stack.

Logo by the Leptos maintainers. MIT · unmodified

Web framework

Vue

Vue

Vue powers the components of our public website, from navigation and documentation to other interactive areas. It helps us keep those interfaces cohesive and extensible.

Logo © Evan You. CC BY-NC-SA 4.0 · unmodified

Library for Discord

Twilight

Twilight

We use Twilight to connect to Discord. The library links our bot written in Rust to Discord.

Logo by Fezhoof. CC BY-SA 4.0 · unmodified

Database

Dragonfly is our shared temporary data store for Discord events, coordination of shards and multiple gateway connections, AutoMod and activity logs.

Software under BSL 1.1 with an additional use grant.

Relational database

PostgreSQL complements our data layer for relational data and structures. It runs alongside ScyllaDB as a separate part of our infrastructure.

Object storage

We use RustFS for S3-compatible object storage. It adds a separate storage layer alongside PostgreSQL and ScyllaDB.

Software under Apache 2.0. RustFS is a trademark of RustFS, Inc.