Skip to content

Algorilla

Detect algorithmic complexity anti-patterns in your codebase.

Algorilla is a static analysis tool that finds hidden O(n²) and O(n·m) performance issues in Java, Kotlin, Groovy, and JavaScript/TypeScript code. It analyzes your source code without executing it, identifying patterns where a simple refactoring can turn quadratic behavior into linear.

  • Getting Started

    Install algorilla, run your first scan, and configure rules for your project.

    Quick start

  • Rules

    Browse all 28 built-in rules with examples, detection logic, and suggested fixes.

    Rules overview

  • Languages

    Java (GA), Kotlin (Alpha), Groovy (Beta), JavaScript/TypeScript (Beta) — parser details, framework knowledge, and rule coverage per language.

    Language support

  • Guide

    CLI reference, CI/CD integration, baseline workflows, and more.

    User guide

  • Learn

    Why performance patterns hide in clean code, how Big-O works, and how algorilla detects them.

    The hidden O(n²) problem

  • Developer

    Architecture, coding conventions, and how to add new rules or language parsers.

    Developer docs

  • Changelog

    What's new in each release.

    Changelog

  • Stability

    What's stable, what's experimental, and how we evolve without breaking you.

    Stability & Compatibility

  • FAQ

    Common questions about confidence, types, suppression, comparisons with other tools, and more.

    Frequently asked questions

Quick example

Point algorilla at your project:

algorilla /path/to/your/project
# or: algorilla --input /path/to/your/project

Algorilla scans your source files and reports what it finds. Here it detected a List.contains() call inside a for-each loop — meaning every iteration does a linear scan of discountedProductIds, making the whole method O(n²). Not sure why that's a problem? Read the hidden O(n²) problem first.

⏺ src/main/java/com/example/shop/service/OrderService.java (1 finding)

     warning  · nested-lookup · Loop amplifiers · O(orders × discountedProductIds) → O(orders + discountedProductIds)
    com.example.shop.service.OrderService:45

      Linear contains on 'discountedProductIds' inside for-each loop
      → Build a HashSet/Map from 'discountedProductIds' before the loop
      ↗ https://tvinke.github.io/algorilla/rules/nested-lookup

          38 │ public List<Order> applyDiscounts(List<Order> orders, List<String> discountedProductIds) {
          44 │ for (Order order : orders) {
          45 │     if (discountedProductIds.contains(order.getProductId())) {
          46 │         matched.add(order);

      ⎿  for-each loop over orders OrderService.java:44 O(orders)
        ⎿  contains on 'discountedProductIds' OrderService.java:45 O(discountedProductIds) ← bottleneck

Scanned 127 files in 0.4s. Found 1 issue (1 warning) across 1 file.
Reading the output

Reading from top to bottom: the severity, rule name, category, and complexity trade-off are on the first line. Below that, a description explains the problem in plain language, followed by a concrete suggestion and a link to the rule's docs page. The code snippet shows the exact lines involved, and the evidence chain (the tree at the bottom) traces the path from outer loop to bottleneck. The fix here: convert discountedProductIds to a HashSet before the loop for O(1) lookups. See understanding output for the full format reference.

What it finds

Category Examples What it catches
Loop amplifiers Nested lookup, repeated regex, IO in loop, ... Expensive work inside loops that multiplies cost per iteration
Sort abuse Sort for last, expensive comparator, filter after sort Sorting entire collections when a simpler operation would do
Query patterns N+1 query, bulk load for single lookup Database/service calls that could be batched into one
Construction cost Heavyweight object per invocation Expensive objects created repeatedly instead of reused
Redundancy Redundant calls, uncached getters, chained getters Same work done multiple times when once would suffice

Deep dives

These pages walk through how specific patterns hide in real code, step by step:

  • The hidden O(n²) problem — how List.contains() inside a loop creates quadratic behavior that hides behind method calls and layers of indirection
  • The hidden triple scan — how clean, readable stream pipelines quietly traverse the same collection multiple times
  • The hidden N+1 — how a simple findById() in a loop turns into thousands of database round-trips that only surface in production

Why algorilla?

Most static analyzers focus on correctness — null checks, type errors, security flaws. Algorilla focuses on algorithmic cost: the patterns that look fine in tests with small data but become expensive at production volumes. A List.contains() inside a loop looks harmless until the list has 10,000 entries.

What it offers:

  • 28 built-in rules across 6 categories, each with evidence chains that show why it's a problem
  • Multi-language: Java, Kotlin, Groovy, JavaScript/TypeScript (including .vue single-file components and JSX)
  • Cross-file analysis: follows call chains across files and languages to catch indirect patterns
  • Fast: analyzes 500+ files/second with incremental caching
  • Zero config: works out of the box with automatic project detection

New to Algorilla?

If you're evaluating the tool or just want to understand what it does, this reading order gets you there quickly:

  1. The hidden O(n²) problem — see how performance bugs hide in clean code (10 min read)
  2. Quick start — install and run your first scan (2 min)
  3. Pick your language — Java, Kotlin, Groovy, or JS/TS — see framework-specific examples
  4. Browse the rules — 28 rules with plain-language impact descriptions

Already installed? Jump to the workflow guide or add it to CI.

Next steps

  • Try it on your projectInstallation takes under a minute. Run it, see what it finds.

  • Browse the rules28 rules with before/after examples so you know exactly what to look for.

  • Add it to CICI/CD integration with GitHub Actions, GitLab CI, and baseline workflows.

  • Understand the outputEvidence chains explain every finding step by step.