Hardware Sizing for Self-Hosted DefectDojo Pro (Pro)

Sizing a DefectDojo deployment comes down to two questions. How much data are you holding, and how many people are working in it at once. This page gives starting points for both.

Treat what follows as general guidance rather than a specification. The figures lean deliberately conservative, and they assume a deployment doing everyday triage alongside regular scan imports. Your own numbers will move depending on how you use the Asset, so read the notes under the table before you provision anything.

Specs are given as generic vCPU and memory figures so they apply to any cloud provider or on-premise hardware. The sizing table has a tab for each deployment method: Kubernetes runs the application tier as pods across nodes and scales out, while Docker Compose runs everything on one host and scales up. Whichever you choose, read Sizing and tuning the application tier too, where the two differ most.

Sizing table

How to read these numbers

Database memory matters more than database CPU

DefectDojo runs aggregation-heavy queries across your findings. Those stay fast while the working set and its indexes are served from memory, and they degrade quickly once the database starts reaching for disk. When you have to choose, buy memory before you buy cores. The table reflects that. Memory roughly doubles from tier to tier while CPU counts move much more slowly.

The application tier tracks users, not findings

The concurrent user figures in the table assume smaller datasets belong to smaller teams. That assumption breaks often. If you hold 200K findings but have 100 people in the UI at once, size the application tier for the users and leave the database where your finding count puts it. The two scale independently.

There is one exception, at the far end of the table. Import and deduplication run on the application tier rather than in the database, so once a data set is large enough for that work to dominate, the application tier follows ingest volume instead of user count. That is why the 500M row sits well above what its user figure on its own would suggest.

Sizing and tuning the application tier

The “Application nodes” column is the compute the application tier needs. How you provide it, and what you have to do to make the application actually use it, is where the two deployment methods differ.

Storage

Plan on 20โ€“30 GB of database storage per million findings. Where you fall in that spread depends on how much you hang off each finding. Long descriptions and large endpoint counts push you toward the top of it. The finding rows themselves are a small part of this. Most of the space goes to indexes and to the related tables that hang off each finding, so sizing from row data alone will leave you well short.

Every tier through 10M fits inside a few hundred GB of general-purpose SSD. Storage is cheap next to the cost of running out, so provision for where you expect to be in a year rather than where you are now. If your provider offers storage autoscaling, turn it on.

The 500M row is sized at 2.5 TB. That figure assumes the live data set is actively managed, with older findings archived out of the hot path rather than accumulating indefinitely. Applied naively, the per-million rate above would put an unmanaged 500M deployment several times higher. If you are heading toward this scale, treat the archiving strategy as part of the sizing exercise rather than something to sort out later.

Storage at this scale also needs attention to throughput, not only capacity. Once the working set stops fitting in memory, default baseline IOPS on general-purpose volumes becomes the limit well before capacity does.

Media storage is separate and usually much smaller. It holds uploaded artifacts such as screenshots and risk acceptance documents, so size it from your own upload habits.

What pushes you up a tier

Finding count is the headline number, but several things will have you sizing up sooner than the count alone suggests.

  • Import volume and frequency. Large scans arriving often, especially several at the same time, put sustained load on both the database and the async workers. CI pipelines that import on every build are the usual cause.
  • Deduplication. Deduplication compares incoming findings against what you already hold. The more findings you have and the broader your deduplication configuration, the more work every import does.
  • Reporting and dashboards. Metrics views and large report generation are read-heavy, and they hit the database harder than day-to-day triage does.
  • API traffic. Integrations that poll or pull large result sets add concurrent load that never shows up in your interactive user count.
  • Retention. Deployments that keep everything forever grow into the next tier on schedule. Archiving or deleting old data keeps you where you are for longer.

Very large deployments

Past the 10M tier, hardware stops being the whole answer. Two things change.

The binding constraint moves from reading to writing. Deduplication compares each incoming finding against what you already hold, so the cost of an import grows with the size of the data set behind it. At the top of the table this is usually what you hit first, ahead of anything users notice in the UI. Whatever import volume built a data set that large is generally still running, so you pay that cost continuously rather than once.

The memory figures assume the hot set stays small. A deployment works recent findings and leaves older ones largely untouched, which is what lets a database hold far more data than it has memory and still perform well. If your access pattern is genuinely spread across the whole data set, you will need more memory than the table lists, and past a point no single instance will have enough.

Both of those point at the same work. Partitioning and archiving cold findings out of the live data set matter more at this scale than another increment of vCPU, and heavy reporting belongs on a read replica rather than on the primary. Plan for that alongside the hardware rather than after it, and talk to us before you provision.

When in doubt, round up

The figures here already lean conservative, and being one size too large costs far less than being one size too small. Database memory pressure in particular does not degrade gracefully. Performance holds up fine until it doesn’t.

Adding application capacity later is straightforward: on Kubernetes you add pods or nodes, and on Docker Compose you resize the host and raise the process and worker counts as above. Resizing a database typically means downtime, so that is the one worth getting right up front.

Questions or support

These are starting points, not limits. If your deployment sits at the top of the table, or your workload doesn’t resemble the assumptions here, talk to us before you provision. Contact your account representative or .