---
import Base from '../layouts/Base.astro';
import SiteNav from '../components/ui/SiteNav.astro';
import Footer from '../components/sections/Footer.astro';
import {
matrixTools,
matrixRows,
coreRows,
performanceFeatures,
uniqueFeatures,
pricingRows,
type ToolKey,
type Cell,
type MatrixRow,
} from '../data/compare';
const multiTables: { num: string; title: string; rows: MatrixRow[]; minW: string; footnote?: string }[] = [
{
num: '01',
title: 'Capability matrix',
rows: matrixRows,
minW: 'min-w-[820px]',
footnote:
'✓ out of the box · — not available · text = caveat (paid tier / partial / different mechanism). Check each vendor for current details.',
},
{
num: '02',
title: 'Core attributes',
rows: coreRows,
minW: 'min-w-[860px]',
},
];
---
<Base
title="foxguard vs Semgrep, OpenGrep, CodeQL, Snyk Code & SonarQube"
description="foxguard vs Semgrep, OpenGrep, CodeQL, Snyk Code, and SonarQube on speed, taint analysis, post-quantum auditing, and price."
>
<div class="sticky top-0 z-40 bg-noir-950 border-b border-noir-800">
<div class="max-w-5xl mx-auto px-6">
<SiteNav backLabel="compare" />
</div>
</div>
<main class="pt-8 pb-24">
<div class="max-w-5xl mx-auto px-6">
<header class="mb-12 max-w-3xl">
<h1 class="font-heading text-3xl sm:text-4xl text-noir-50 tracking-tight mb-3">How foxguard compares</h1>
<p class="text-noir-500 text-base leading-relaxed">
How foxguard compares with Semgrep, OpenGrep, CodeQL, Snyk Code, and SonarQube on speed,
taint analysis, post-quantum readiness, and price. Figures come from each vendor's docs.
</p>
</header>
{/* 01 Capability matrix + 02 Core attributes share the multi-tool table layout */}
{multiTables.map((tbl) => (
<section class="mb-16">
<h2 class="font-heading text-noir-50 text-xl sm:text-2xl mb-6 flex items-center gap-2">
<span class="text-fox-light font-mono text-sm">{tbl.num}</span>
{tbl.title}
</h2>
<div class="rounded-xl border border-noir-800 overflow-hidden">
<div class="overflow-x-auto">
<table class={`w-full text-left ${tbl.minW}`}>
<thead>
<tr class="border-b border-noir-800 bg-noir-900/50">
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider sticky left-0 bg-noir-900/50">
{tbl.title === 'Core attributes' ? 'Attribute' : 'Capability'}
</th>
{matrixTools.map((tool) => (
<th class={`px-4 py-2.5 text-xs font-medium uppercase tracking-wider ${tool.key === 'foxguard' ? 'text-fox-light' : 'text-noir-500'}`}>
<span class="block whitespace-nowrap">{tool.label}</span>
<span class="block text-[10px] font-normal normal-case tracking-normal text-noir-600 mt-0.5">{tool.tagline}</span>
</th>
))}
</tr>
</thead>
<tbody>
{tbl.rows.map((row) => (
<tr class="border-b border-noir-800/40 last:border-b-0">
<td class="px-4 py-2.5 text-sm text-noir-300 align-top sticky left-0 bg-noir-950">
<span class="block whitespace-nowrap">{row.capability}</span>
{row.note && <span class="block text-[11px] text-noir-600 mt-0.5 whitespace-normal max-w-[260px]">{row.note}</span>}
</td>
{matrixTools.map((tool) => {
const val: Cell = row.cells[tool.key as ToolKey];
const isFox = tool.key === 'foxguard';
return (
<td class="px-4 py-2.5 text-sm align-top">
{val === 'yes' ? (
<span class="text-sage-light">✓</span>
) : val === 'no' ? (
<span class="text-noir-700">—</span>
) : (
<span class={isFox ? 'text-noir-100 font-medium' : 'text-noir-400'}>{val}</span>
)}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
</div>
{tbl.footnote && <p class="text-noir-600 text-xs mt-3">{tbl.footnote}</p>}
</section>
))}
{/* 03 Performance — the one head-to-head we actually measured */}
<section class="mb-16">
<h2 class="font-heading text-noir-50 text-xl sm:text-2xl mb-6 flex items-center gap-2">
<span class="text-fox-light font-mono text-sm">03</span>
Performance
</h2>
<div class="rounded-xl border border-noir-800 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left min-w-[520px]">
<thead>
<tr class="border-b border-noir-800 bg-noir-900/50">
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider">Metric</th>
<th class="px-4 py-2.5 text-xs font-medium text-fox-light uppercase tracking-wider">foxguard</th>
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider">Semgrep</th>
</tr>
</thead>
<tbody>
{performanceFeatures.map((row) => (
<tr class="border-b border-noir-800/40 last:border-b-0">
<td class="px-4 py-2.5 text-sm text-noir-300">{row.feature}</td>
<td class="px-4 py-2.5 text-sm text-noir-100 font-medium">{row.foxguard}</td>
<td class="px-4 py-2.5 text-sm text-noir-400">{row.semgrep}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<p class="text-noir-600 text-xs mt-3">
Same hardware and rulesets; reproduce with <code class="text-noir-500">./benchmarks/run.sh</code>.
OpenGrep forks the Semgrep engine, so its numbers track Semgrep. CodeQL builds a database before it can query
and SonarQube runs as a server. Both are heavier by design and are not sub-second local tools.
</p>
</section>
{/* 04 Unique to foxguard */}
<section class="mb-16">
<h2 class="font-heading text-noir-50 text-xl sm:text-2xl mb-6 flex items-center gap-2">
<span class="text-fox-light font-mono text-sm">04</span>
Unique to foxguard
</h2>
<div class="rounded-xl border border-noir-800 bg-noir-900/30 p-6 sm:p-8">
<p class="text-noir-500 text-sm mb-6">None of the other five ship these out of the box:</p>
<ul class="grid sm:grid-cols-2 gap-x-8 gap-y-5 list-none pl-0">
{uniqueFeatures.map((f) => (
<li>
<div class="flex items-baseline gap-2">
<span class="text-fox-light flex-shrink-0">✓</span>
<span class="text-noir-100 text-sm font-medium">{f.feature}</span>
</div>
<p class="text-noir-500 text-xs leading-relaxed mt-1 pl-6">{f.note}</p>
</li>
))}
</ul>
</div>
</section>
{/* 05 Pricing & licensing */}
<section class="mb-16">
<h2 class="font-heading text-noir-50 text-xl sm:text-2xl mb-6 flex items-center gap-2">
<span class="text-fox-light font-mono text-sm">05</span>
Pricing & licensing
</h2>
<div class="rounded-xl border border-noir-800 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left min-w-[680px]">
<thead>
<tr class="border-b border-noir-800 bg-noir-900/50">
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider">Tool</th>
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider">License</th>
<th class="px-4 py-2.5 text-xs font-medium text-noir-500 uppercase tracking-wider">Cost model</th>
</tr>
</thead>
<tbody>
{pricingRows.map((row) => {
const isFox = row.tool === 'foxguard';
return (
<tr class="border-b border-noir-800/40 last:border-b-0">
<td class={`px-4 py-2.5 text-sm align-top whitespace-nowrap ${isFox ? 'text-fox-light font-medium' : 'text-noir-300'}`}>{row.tool}</td>
<td class="px-4 py-2.5 text-sm text-noir-400 align-top">{row.license}</td>
<td class="px-4 py-2.5 text-sm align-top">
<span class={isFox ? 'text-noir-100 font-medium' : 'text-noir-400'}>{row.cost}</span>
<span class="block text-[11px] text-noir-600 mt-0.5 whitespace-normal">{row.note}</span>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
<p class="text-noir-600 text-xs mt-3">
Terms change; figures reflect each vendor's published model, not a quote.
</p>
</section>
{/* Summary */}
<section class="mb-16">
<div class="rounded-xl border border-noir-800 bg-noir-900/30 p-8">
<h2 class="font-heading text-noir-50 text-xl mb-4">When to pick foxguard</h2>
<ul class="space-y-2 text-sm text-noir-400 leading-relaxed list-none pl-0">
<li class="flex gap-3"><span class="text-fox-light flex-shrink-0">✓</span>You want a fast, free scanner that runs without a login or token limits.</li>
<li class="flex gap-3"><span class="text-fox-light flex-shrink-0">✓</span>You need post-quantum crypto auditing (CNSA 2.0) or a CBOM.</li>
<li class="flex gap-3"><span class="text-fox-light flex-shrink-0">✓</span>You want a single static binary that runs without a runtime or database build.</li>
<li class="flex gap-3"><span class="text-fox-light flex-shrink-0">✓</span>You need cross-file taint for Python, JS, Go, Java, Ruby, PHP, C#, or Kotlin without a paid license.</li>
</ul>
<h2 class="font-heading text-noir-50 text-xl mt-8 mb-4">When another tool might fit better</h2>
<ul class="space-y-2 text-sm text-noir-400 leading-relaxed list-none pl-0">
<li class="flex gap-3"><span class="text-noir-500 flex-shrink-0">→</span><span><span class="text-noir-300">Semgrep / OpenGrep</span> for a native custom-rule DSL, or 30+ languages including Scala and Terraform.</span></li>
<li class="flex gap-3"><span class="text-noir-500 flex-shrink-0">→</span><span><span class="text-noir-300">CodeQL</span> for GitHub Advanced Security with deep QL queries and in-platform code scanning.</span></li>
<li class="flex gap-3"><span class="text-noir-500 flex-shrink-0">→</span><span><span class="text-noir-300">Snyk Code / SonarQube</span> for a managed SaaS or server with team dashboards, policy gates, and quality metrics.</span></li>
</ul>
</div>
</section>
{/* CTA */}
<section class="text-center">
<h2 class="font-heading text-noir-50 text-2xl sm:text-3xl mb-4">Try foxguard on your codebase</h2>
<p class="text-noir-500 text-sm mb-6">Run one command to scan your code for free. No config or signup required.</p>
<div class="inline-flex rounded-xl border border-noir-800 overflow-hidden">
<code class="px-5 py-3 font-mono text-sm text-fox-light">npx foxguard .</code>
</div>
<div class="flex items-center justify-center gap-4 mt-6">
<a href="/docs" class="text-sm text-noir-500 hover:text-noir-100 transition-colors no-underline">Read the docs →</a>
<a href="/rules" class="text-sm text-noir-500 hover:text-noir-100 transition-colors no-underline">Browse all rules →</a>
</div>
</section>
</div>
</main>
<Footer />
</Base>