# Jamdesk - Complete Site Content > This file contains the complete textual content of jamdesk.com for LLM consumption. > For a table of contents, see: https://www.jamdesk.com/llms.txt --- ## Jamdesk - Software Documentation Tool for Developers URL: https://www.jamdesk.com/ # Documentation software.AI included. Jamdesk builds fast, AI-ready docs sites from MDX in your Git repo. Includes analytics, white labeling, and custom domains. No add-ons, just $29/mo. Start free trialSee FeaturesJamdeskDeploying docs.mycompany.comClone repositoryValidate configBuild pagesUpload to CDNGenerating AIPurge cacheTotal0.0s ⚡Your docs are live ## Everything you need for modern docs Modern documentation software that handles building, deploying, and optimizing your docs. See it live in the Jamdesk docs ### AI Chat, Included Natural language search that understands your docs. Users find answers instantly, not just keyword matches. How do I authenticate with OAuth?↳ Authentication → /auth/oauth↳ Quick Start → /getting-started ### Deploy in Seconds Push to GitHub, see your docs live in under a minute. No CI pipelines, no infrastructure to manage. Clone & validate0.5sBuild pages1.8sDeploy to CDN0.9s ### Edit in Your Browser Create, edit, and publish pages from the dashboard with a live preview. No code editor needed. Every save is a real Git commit. intro.mdx# Quick Start  Install the CLI to get ### Four Designed Themes Jam, Nebula, Pulsar, and Halo look right with zero CSS. Customize colors, fonts, and layout to match your brand. JamNebulaPulsarHalo ### Blazing-Fast Page Loads Global CDN, optimized builds, and edge delivery. Your users get answers in milliseconds, not seconds. First paint0.4sFully loaded0.8sCDN cache hit12ms ### One Price, Everything Included All AI features, analytics, white labeling, and custom domains — $29/mo flat. No upsells, no AI credit meters. Ask AI chat, Fix with AI, AI ScoreAnalytics dashboardWhite labelingCustom domainsReal human support ### A Real CLI Full control from your terminal — and your AI agent. Build, validate, migrate, and debug with one command. jamdesk$jamdesk devhot-reload preview$jamdesk deployship to production$jamdesk fixauto-fix broken links$jamdesk migratefrom any tool50+ featuresAI & AgentsWrite & PublishPerformance & SpeedDeveloper ExperienceSearch & DiscoveryAnalytics & InsightsDesign & BrandComponents & Content ## How it works Docs as code. From writing to production in three simple steps. 1 ### Write MDX Author content in MDX — in your own editor or right in the browser — with 25+ built-in components. Callouts, tabs, code blocks, and more. # Quick Start  Install the CLI to begin.2 ### Push to GitHub Commit and push. Jamdesk detects changes, builds your site, and deploys automatically. git commit -m "update"git push origin mainBuild triggered3 ### Docs Go Live Your documentation is deployed to a global CDN in seconds, with SSL and custom domain support. docs.mycompany.comSSL · Global CDN · 99.9% uptimeLive · 3.2s deploy ## Ensure your docs are found by the leading LLMs Every Jamdesk site auto-generates llms.txt and llms-full.txt following the open standard. AI assistants can instantly understand your entire docs site. No configuration and no extra charge. ChatGPTClaudeCopilotGemini ## Why companies choose Jamdesk Jamdesk takes the complexity out of building and running your own documentation platform, so you get a docs site without the engineering overhead. ### Ship faster, for less You launch without spinning up a dedicated docs team or wiring together a site generator, hosting, and a build pipeline. Your documentation goes live on day one, and your engineers stay focused on the product. ### Best practices, built in Jamdesk works with your git repository and arrives with clean navigation, AI chat, and pages that AI assistants can read. You get the conventions that strong docs teams spend years discovering, ready from your first commit. ### We handle the hard parts Hosting, global CDN, search, and SEO all run for you at pricing that stays friendly as you grow. Your team writes the documentation, and Jamdesk takes care of everything around it. ## Let your AI agents ship docs Your content lives as MDX files in Git. AI agents edit them and can even control the pipeline via CLI. Claude Code>Add an authentication guide to the docsI'll add an authentication section to the getting started guide.Edited getting-started.mdx (+24 lines)Now I'll build and deploy your docs.jamdesk buildBuilding 12 pages... done (1.8s)jamdesk deployDeploying to docs.mycompany.com...✓ Live in 3.2s ## Easily switch to Jamdesk The Jamdesk migration tool will get your docs up and running in minutes from Mintlify, GitBook, Readme, or Document360. ### One-Command Migration Run `jamdesk migrate` and your pages, navigation, and config are converted in minutes. Existing components just work. ### 25+ MDX Components Everything you already use, plus components others don't have: File Tree, Changelog, Framework Switcher, and more. ### Your Content, Your Git Repo MDX files live in your repository, reviewed through PRs, deployed on push. No proprietary format, no CMS lock-in. ### Real Humans Giving Real Support Your readers get instant AI answers in your docs. You get a real human — every time. We're a small team, so replies can take a little longer, but you'll always reach a person who built the product. No bots, no ticket queue. $ npx jamdesk migrate Detecting existing docs config... Converting config... done Migrating MDX components... done ✓ Migration complete. Run jamdesk dev to preview. ## Ship better docs for $29/mo Documentation software with AI chat, analytics, and white labeling — all included. Start free trialor see pricing details → --- ## Pricing — Jamdesk Documentation Tool URL: https://www.jamdesk.com/pricing # Simple transparent pricing includes all the features Documentation software pricing built for teams of every size. Start with a free trial and upgrade when you're ready. MonthlyAnnualSave 17% ### Free Trial Freefor 14 days Full access to every feature for 14 days. Cancel anytime. Start free trial - All Pro features included - Unlimited team members included - 14 days of unlimited access - Custom domain support - Built-in analytics - Real human supportMost Popular ### Pro $29per month Everything you need, nothing you don't. Scales with your team. Start free trial - Unlimited documentation pages - Unlimited team members included - Web editor with live preview - All AI features unmetered — Ask AI Chat, Fix with AI, AI Score - Built-in MCP server - SEO and GEO optimized - Custom domain with SSL - Site & page password protection - Built-in analytics dashboard - Interactive API playground - Remove Jamdesk branding - Real human support ### Enterprise Customfor large teams Tailored solutions with dedicated support and custom integrations. Contact Sales - Everything in Pro - Dedicated account manager - Custom SSO/SAML - Volume discounts - SLA guarantee - Regional hosting (EU/US data residency) - Security review ### Need more? Pro scales with you. Pro includes 1 docs project and unlimited team members. Add more projects anytime. Extra docs project$15/mo or $150/yearVolume discountsAvailable on Enterprise ### Compare features FeatureFree TrialProEnterpriseUnlimited pagesUnlimited team membersCustom domainSSL certificatesRemove brandingBuilt-in analyticsSite & page password protectionAsk AI ChatMCP server (built-in)SEO and GEO (AI) optimizationAI Score (agent-readiness)AI-powered docs fixes (Fix with AI)Real human supportInteractive API playgroundBuild-time OpenAPI validationAPI accessCustom JavaScript and CSSWeb editor with live previewBroken link detection, auto-fix & spellcheckPDF exportImage optimization25+ MDX components100+ syntax languagesDocs Search APIMultiple projectsCustom SSO/SAMLDedicated account managerSLA guaranteeRegional hosting (EU/US data residency) ## Pricing questions The short answers. For everything else, see our full FAQ. What happens after my 14-day trial?After 14 days, you can upgrade to a paid plan to continue. If you don't, your docs site is paused (not deleted) until you decide.Does Jamdesk offer discounts or coupon codes?We don't use coupon or promo codes — any site claiming to have Jamdesk coupon codes is not affiliated with us. There are two real ways to save: annual billing cuts your price by 17% compared to monthly, and Enterprise plans include volume discounts. Every plan also starts with a 14-day free trial, so you can try every feature before paying anything.Who counts as a team member, and is there a limit?Editors and admins in your dashboard count as team members — every plan includes unlimited team members at no extra charge. Your public docs readers are always free too, no matter how many people visit.Does Jamdesk meter or bill AI features by credits?No. Every plan includes all AI features — Ask AI chat for your readers, Fix with AI for automated doc fixes, and AI Score on every build — with no credit meters or overage charges. Many documentation platforms meter AI with monthly credit pools and per-credit overage billing; Jamdesk doesn't.Can I password-protect my docs site?Yes — lock the whole site or just specific pages behind a shared password. See Password protection. Enterprise plans also include SSO for both the dashboard and your docs site — see SSO setup.How are my docs secure?Security is one of our core priorities — every site gets automatic SSL, with optional password protection or SSO for private content. For the full picture on our infrastructure, data handling, and compliance, see our docs security overview, security page, and DPA.How do I migrate from another platform?We provide migration tools for Mintlify and other platforms. Run npx jamdesk migrate in your project directory — it auto-detects your platform and imports your docs. Most migrations take less than an hour. See our migration guide. Have an audience of developers or technical writers? Join the Jamdesk affiliate program and earn 30% recurring → ## Ready for Enterprise? Get in touch with our team to discuss custom solutions for your organization. WebsiteFull NameCompany NameWork EmailMessageContact Sales --- ## Features — Jamdesk Software Documentation Tool URL: https://www.jamdesk.com/features # Everything you need to ship docs your readers and their AI assistants can both use Documentation software for writing, customizing, analyzing, and shipping your docs. All included, no add-ons required. ## AI & Agents Your docs talk to ChatGPT, Claude, Cursor, and every agent in between. Terminal$claude mcp add jamdesk-docs https://docs.site.com/mcpMCP server ready — 247 pages indexed ### Built-in MCP Server Every Jamdesk site ships with a Model Context Protocol server. Claude, Cursor, ChatGPT, and any MCP-aware tool can connect to your docs as a live knowledge source. Nothing to host, nothing to configure. Terminal$curl docs.site.com/llms.txt# AI-friendly index... ### llms.txt Generation AI-friendly content index following the llmstxt.org specification. ### Full Markdown Export Complete documentation in a single file for large context windows. ### Individual Page Markdown Each page available as plain markdown at /docs/*.md. ### Structured Schema.org Data Machine-readable metadata for better AI understanding. ### SEO and GEO Optimized Classic SEO best practices plus Generative Engine Optimization (GEO), the practice of structuring content so AI assistants like ChatGPT, Claude, and Perplexity quote and cite it when users ask questions. Answer-first headings, structured data, citation-ready markup, and machine-readable exports get your docs surfaced in Google search and AI Overviews. ### Docs Search API Query your documentation from Intercom, Zendesk, Slack bots, or any tool with a simple REST API. Semantic search powered by the same AI that runs your docs chat. ### AI Score Every build is graded on how easily AI agents like ChatGPT and Claude can read your docs. See your score, a per-category breakdown, the trend over time, and a copy-ready fix prompt for your AI editor — right in your dashboard. ## Write & Publish From markdown to live docs in seconds intro.mdx 1# Welcome234 Interactive MDX!567## Getting Started ### MDX Support Markdown with embedded React components for interactive documentation. multi-lang const api = new Jamdesk();await api.deploy();// Pythondef hello(): print("Hello!") ### 100+ Language Syntax Highlighting Shiki-powered code blocks with support for every programming language. ### Web Editor Create, edit, and publish pages right in your browser, with a live preview beside you. No clone, no terminal — every save is a real Git commit that rebuilds your site automatically. ### Git-Based Workflow Push to GitHub, deploy automatically. No manual steps required. ### Local Development Server Hot reload preview as you write with our CLI tools. ### LaTeX/KaTeX Support Beautiful math equations rendered inline or as blocks. ### Frontmatter Metadata Control page titles, descriptions, icons, and SEO settings. ### PDF Export Export your entire docs site as a single PDF. One click from the dashboard, delivered by email, included on every paid plan. ## Performance & Speed Docs that load fast and rank well Edge Response Time$curl -w '%{time_total}s' https://docs.example.com0.043s ### Global CDN Delivery Every page served from edge locations worldwide. Your users get fast loads no matter where they are. ### Optimized Static Builds Pre-rendered pages with optimized assets. No server-side rendering delays. ### Image Optimization Automatic WebP conversion, lazy loading, and responsive sizing for screenshots and diagrams. ### Minimal JavaScript Documentation pages ship lean. Interactive components load only when needed. ### Instant Navigation Client-side routing with prefetching. Page transitions feel instant. ### Core Web Vitals Optimized Built to pass Google's page experience signals. Good for SEO, great for users. ## Developer Experience Tools developers love openapi.yaml openapi: 3.0.0paths: /users: get: summary: List users ### OpenAPI Auto-Generation Generate beautiful API docs from your OpenAPI 3.0+ specs. Jamdesk doubles as full API documentation software — references regenerate on every build as your spec evolves. Terminal$jamdesk devServer running at localhost:3000$jamdesk validateAll files valid!$jamdesk fix -yFixed 3 broken links.$jamdesk spellcheckChecked 247 pages — no misspellings found. ### CLI Tools jamdesk dev, validate, broken-links, spellcheck, and doctor commands. Catch typos and broken links before they ship, then auto-fix them with jamdesk fix. OpenAPI specs are validated automatically on every cloud build, with an email and dashboard alert if one breaks. ### Interactive API Playground Try endpoints live from the docs. Authenticated requests, real responses, copy-as-cURL. All generated from your OpenAPI spec — a REST API documentation tool with live, multi-language examples. ### Multi-Language Code Examples Automatic cURL, JavaScript, Python, Go examples from specs. ### Mintlify Migration Import existing Mintlify docs with our migration tool. ### Monorepo Support Configure docs.json path for projects in subdirectories. ### Redirects URL redirects with exact paths, :slug* wildcards, and trailing * patterns. ### Multi-Language Docs Support for multiple languages with automatic detection. ### Build Webhooks Automatic builds triggered by GitHub push events. ## Search & Discovery Help users find what they need How do I authenticate users?AIAuthentication GuideLearn how to set up API keys...JWT TokensUsing JSON Web Tokens... ### AI-Powered Search Natural language queries that understand intent, not just keywords. ### Built-in Full-Text Search Cmd+K powered search with instant results, no configuration needed. ### SEO Optimized Automatic meta tags, Open Graph images, and structured data. ### Automatic Sitemap XML sitemaps generated at build time, respecting noindex pages. ### Recent Searches Quick access to previously searched terms. ## Analytics & Insights Understand your documentation ### Built-in Analytics Dashboard Visitors, page views, and traffic sources without third-party tools. ### Geographic Heatmap See where your users come from around the world. ### Popular Pages Tracking Identify your most valuable content and gaps. ### Technology Breakdown Browser, OS, and device statistics for your audience. ### Privacy-Focused No cookies required, GDPR friendly by design. ### 11+ Analytics Integrations Google Analytics, Plausible, PostHog, Amplitude, Mixpanel, and more. ## Design & Brand Make it yours, beautifully JamNebulaPulsarHalo ### 4 Professional Themes Jam (clean, modern), Nebula (airy, developer-friendly), Pulsar (sharp, high-contrast), and Halo (warm, rounded). ### Custom Branding Your logo, colors, and favicon. Light and dark variants supported. ### Custom Domains Use docs.yoursite.com with automatic SSL certificates. ### Subpath Hosting Host at yoursite.com/docs with full proxy support for Vercel, Cloudflare, and more. ### White Label Remove Jamdesk branding completely on all plans. ### Dark Mode Automatic theme switching that respects system preferences. ### Custom Fonts Configure heading and body fonts with Google Fonts or self-hosted. ### Custom CSS Add your own styles for complete control over appearance. ### Custom JavaScript Drop in analytics scripts, chat widgets, A/B testing snippets, or any third-party tag. Loaded at the right lifecycle moment so it never blocks the page. ## Components & Content Rich, interactive documentation CardTabsAccordionStepsCalloutCodeTableImageVideoAlertButtonTooltip ### 25+ MDX Components Cards, Tabs, Accordions, Steps, Expandable, Panels, and more. code-groups // JavaScriptfetch('/api/users')# Pythonrequests.get('/api')// Gohttp.Get("/api") ### Code Groups Tabbed code examples showing the same concept in multiple languages. ### Mermaid Diagrams Flowcharts, sequence diagrams, and graphs rendered from text. ### Callouts & Alerts Note, Info, Warning, Tip, Check, and Danger variants. ### API Request/Response Blocks Beautiful endpoint documentation with examples. ### Inline React Components Define custom components directly in your MDX files. ### File Tree Component Display directory structures with syntax highlighting. ### Zoomable Images Click-to-zoom for detailed screenshots and diagrams. ## Ready to get started? Try Jamdesk free for 14 days. Cancel anytime. Start free trialCompare to Alternatives --- ## Compare Documentation Tools — Jamdesk vs Mintlify vs GitBook vs ReadMe vs Document360 vs Redocly vs Fern URL: https://www.jamdesk.com/compare # How Jamdesk compares See how Jamdesk stacks up against Mintlify, GitBook, ReadMe, Document360, Redocly, and Fern Docs. Flat pricing, AI chat included, your content stays in Git. JamdeskYou are hereMintlifyGitBookReadMeDocument360RedoclyFern DocsPricingPricing modelOne flat rateUpsell for featuresPer site + per userUpsell for featuresQuote onlyPer seat (no base)Tiered (free + upsell)Free trial14 days, full featuresFree Starter plan14 days14 days14 days30 days14 days (+ free tier)No surprise feesCore FeaturesUnlimited pages100–500Custom domainsIncludedIncludedIncludedIncludedIncludedIncludedIncludedSubpath hosting (/docs)IncludedDIY proxy setupProxy setupNoReverse proxyIncludedTeam planWhite label (remove branding)All plansEnterpriseEnterpriseEnterpriseCustom CSSEnterpriseEnterpriseNo "Powered by" badgeEnterpriseEnterpriseWeb only (PDF watermark stays)EnterpriseMultiple themesCustomCustom themingPDF exportAll plansEnterprisePremium planPro planAll plansTeam planPerformance & SecurityPage load speedGlobal edge CDNEdge CDNCDNCDNStandardCDNCDNDeploy speed~30 seconds1–2 minManualManualManualManualGit/CIImage optimizationSite & page password protectionAll plansPro planPro planEnterpriseBusiness planEnterpriseTeam planAnalyticsBuilt-in analyticsFull dashboardPro planSite InsightsMetrics productArticle PerformanceEnterpriseTeam planGeographic heatmapTraffic source trackingPro planPremiumBusiness planEnterpriseThird-party integrations20+ toolsLimitedLimitedLimitedBusiness planLimitedLimitedSearch & AIFull-text searchAsk AI ChatUnlimited, no fee10k credits/mo (Pro)500/mo on Ultimate+$150/moEddy: meteredEnterpriseAI credits (250/1k/custom)Built-in MCP serverAll plansAll plansAll plansEnterprisellms.txt generationSEO and GEO (AI) optimizationBuilt-in AI-readiness scoringAutomatic, every buildStandalone toolStandalone toolDeveloper ExperienceOpenAPI supportBuild-time OpenAPI validationAuto, non-blocking + alertsSkips invalid opsOn uploadOn importAutomaticAutomaticInteractive API playgroundBroken link and spellcheckDetect + auto-fixLinks only (manual CLI)Custom JavaScript and CSSAll plansAll plansPro planAll paid plansEnterpriseMigration toolsMintlify importN/AImport toolsImport toolsN/AN/AMigration supportCLI toolsNoNoLocal developmentNoNoComponents & CompatibilityMDX components25+~25~15LimitedLimitedCustom ReactMDX + ReactMintlify component compatibilityOne-command migrationOpenAPI auto-generationMermaid diagramsFile tree component ## Key differences ### Git-first Your docs live as MDX files in your Git repo. No vendor lock-in. If you leave Jamdesk, you take everything with you. ### Flat pricing $29/mo flat. No usage tiers. Analytics, white labeling, and AI chat are included on every plan. ### AI-Native Auto-generates an llms.txt file and ships with a built-in MCP server, so AI tools like Claude and ChatGPT can reference your docs directly. ## Deep dive comparisons See how Jamdesk compares to each alternative in detail. - Jamdesk vsMintlify Flat pricing and no paid upgrades Migrate in one command. Get full component compatibility. Every feature is included on every plan. Read - Jamdesk vsGitBook Analytics and AI chat built in You get a full analytics dashboard and AI chat at no extra cost. Not just page views and paid upgrades. Read - Jamdesk vsReadMe Built for developers without paid upgrades Use CLI tools and local development. Build with MDX components. Pay a flat price instead of paying based on usage. Read - Jamdesk vsDocument360 Built around Git with clear pricing Your developer docs live in your repo. No enterprise knowledge base with hidden pricing. Read - Jamdesk vsRedocly Flat pricing without per-seat math Same first-class OpenAPI support, plus analytics and AI chat on every plan. No per-seat Enterprise tier required. Read - Jamdesk vsFern Docs Flat pricing and docs without the SDK toolchain Both generate API docs from OpenAPI. Jamdesk adds flat pricing, unlimited AI chat, and analytics — without metered AI credits or a 5-seat cap. Read - Jamdesk vsDocusaurus Hosted platform vs a repo you maintain Docusaurus is free and you run it. Jamdesk is flat-rate with hosting, search, analytics, and AI already working on the first build. Read ## Head-to-head comparisons Comparing two vendors against each other? Start here. - GitBook vs Mintlify vs ReadMeThe three-way docs platform comparison - Mintlify vs Document360Developer docs vs knowledge base - Mintlify vs GitBookThe two names everyone shortlists - Mintlify vs ReadMeDocs site vs API portal - Fern vs MintlifySDK generation vs developer docs - Mintlify vs RedoclyFlat rate vs per seat - GitBook vs ReadMeKnowledge base vs developer portal - GitBook vs RedoclyBlock editor vs spec-driven docs - Mintlify vs DocusaurusPaid hosting vs your own build - GitBook vs DocusaurusLeast code vs most control ### Migration is easy Already on Mintlify? One command imports your pages, navigation, and configuration. Most migrations take a few minutes. npx jamdesk migrate ## Ready to switch? Try Jamdesk free for 14 days. Set up in under 10 minutes. Start free trialSee all features --- ## FAQ — Jamdesk Documentation Tool URL: https://www.jamdesk.com/faq # Frequently asked questions Everything you need to know about Jamdesk. Can't find what you're looking for? Contact us. What happens after my 14-day trial?After 14 days, you can upgrade to a paid plan to continue. If you don't, your docs site is paused (not deleted) until you decide.Does Jamdesk offer discounts or coupon codes?We don't use coupon or promo codes — any site claiming to have Jamdesk coupon codes is not affiliated with us. There are two real ways to save: annual billing cuts your price by 17% compared to monthly, and Enterprise plans include volume discounts. Every plan also starts with a 14-day free trial, so you can try every feature before paying anything.Who counts as a team member, and is there a limit?Editors and admins in your dashboard count as team members — every plan includes unlimited team members at no extra charge. Your public docs readers are always free too, no matter how many people visit.Does Jamdesk meter or bill AI features by credits?No. Every plan includes all AI features — Ask AI chat for your readers, Fix with AI for automated doc fixes, and AI Score on every build — with no credit meters or overage charges. Many documentation platforms meter AI with monthly credit pools and per-credit overage billing; Jamdesk doesn't.Can I password-protect my docs site?Yes — lock the whole site or just specific pages behind a shared password. See Password protection. Enterprise plans also include SSO for both the dashboard and your docs site — see SSO setup.How are my docs secure?Security is one of our core priorities — every site gets automatic SSL, with optional password protection or SSO for private content. For the full picture on our infrastructure, data handling, and compliance, see our docs security overview, security page, and DPA.How do I migrate from another platform?We provide migration tools for Mintlify and other platforms. Run npx jamdesk migrate in your project directory — it auto-detects your platform and imports your docs. Most migrations take less than an hour. See our migration guide.How does Jamdesk pricing work?Jamdesk uses simple, transparent pricing with one flat rate per month. No surprise usage fees, no hidden costs. You get full access to all features on every plan.What's included in the free trial?The 14-day free trial includes full access to every feature - custom domains, analytics, all AI features (Ask AI chat, Fix with AI, AI Score), all MDX components, and more.Can I use my own domain?Yes! All plans include custom domain support with automatic SSL certificates. You can use docs.yoursite.com or even host at yoursite.com/docs with our subpath proxy support.What's the difference between the themes?Jamdesk offers four professional themes: Jam (clean, modern with Inter font), Nebula (airy, developer-friendly with JetBrains Mono option), Pulsar (sharp, high-contrast for dense technical content), and Halo (warm and soft with rounded cards, for comfortable long-form reading). Each has distinct typography and spacing optimized for different use cases.Do I need to install anything?No installation required for basic use - just push your markdown files to GitHub and we'll build and deploy automatically. For local development, our CLI provides a hot-reload preview server.Can I edit my docs without Git or a code editor?Yes. Jamdesk includes a web editor built into the dashboard: create, edit, and publish pages from your browser with a live preview, no cloning or terminal required. It edits MDX (not a drag-and-drop WYSIWYG canvas), and every change is committed to your connected GitHub repo and deployed automatically - exactly like pushing from your own machine. The editor runs in a desktop browser and needs a GitHub-connected repo.Can I use React components in my docs?Yes! Jamdesk supports MDX, which means you can use React components alongside markdown. We provide 25+ built-in components, including all components from Mintlify, plus exclusives like File Tree, Color Palettes, and Framework Switcher. You can also define custom components directly in your MDX files.How does the built-in analytics work?Our analytics dashboard tracks visitors, page views, traffic sources, geographic locations, and popular pages - all without cookies or third-party scripts. It's privacy-focused and GDPR compliant by design.What is llms.txt?llms.txt is a specification (llmstxt.org) that makes your documentation AI-friendly. Jamdesk automatically generates this file so AI assistants like ChatGPT and Claude can better understand and reference your docs.Can I remove the Jamdesk branding?Yes, white labeling is available on all plans. You can completely remove Jamdesk branding and make your docs site look entirely custom.Do you support OpenAPI specs?Yes! Upload your OpenAPI 3.0+ specification and Jamdesk automatically generates beautiful API documentation with multi-language code examples (cURL, JavaScript, Python, Go, and more). We also validate your spec automatically on every build — if it's malformed, your docs still deploy and we email you the exact error so nothing silently breaks.Can I export my docs as a PDF?Yes. Every paid plan includes PDF export — no add-on, no extra charge. From the dashboard, open Settings → PDF Exports, pick a language (for multi-language projects), and click Generate. You get a download link in the dashboard and by email. Each project can generate up to 3 PDFs per day, with the counter resetting at midnight UTC.Can I have multiple documentation sites?Yes, Pro and Enterprise plans support multiple documentation projects. Each project can have its own domain, theme, and configuration.Is there an API?Yes, Pro and Enterprise plans include API access for programmatic builds, configuration updates, and analytics data retrieval.What support options are available?Every plan includes direct access to the team that built Jamdesk, by email and chat. A real person always answers. We're a small team, so we won't promise instant replies — we promise a human who can actually solve your problem, not a bot or a canned macro. (The AI chat on your docs site is for your readers; when you contact us, you reach a person.) ## Still have questions? Start your free trial and see for yourself, or reach out to our team. Start free trialContact Sales --- ## Jamdesk Affiliate Program — Earn 30% Recurring Commission URL: https://www.jamdesk.com/affiliate-program # Jamdesk Affiliate Program Earn 30% recurring commission for every customer you refer to Jamdesk, with a generous 60-day attribution window. Apply to join30%Recurring commission60 daysAttribution windowRecurringOngoing payouts ## How it works 1 ### Apply Tell us where you'll share Jamdesk. We review every application and approve good-fit partners fast. 2 ### Share your link Once you're approved, you'll get a unique referral link to drop into your posts, videos, newsletters, or docs. 3 ### Earn recurring commission Earn 30% of every payment your referrals make, for as long as they stay. ## Why join the Jamdesk affiliate program ### Recurring revenue Not a one-off bounty. Earn 30% of every invoice your referrals pay, month after month. ### A product people keep Jamdesk turns Markdown into beautiful, AI-ready docs. Easy to recommend, easy to stick with — which means durable commissions for you. ### Fair 60-day attribution A 60-day attribution window means you still get credit when your audience signs up later, not just on the first click. ### Free to join No fees and no minimums to apply. If you have an audience of developers or technical writers, you're a fit. ## Affiliate program FAQ What is the Jamdesk affiliate program?The Jamdesk affiliate program lets you earn recurring commission for referring new customers to Jamdesk, the documentation platform that turns Markdown into beautiful, AI-ready docs. Share your referral link and earn a share of every payment your referrals make.How much can I earn as a Jamdesk affiliate?You earn 30% recurring commission on every payment a referred customer makes, for as long as they stay a paying customer. Because it's recurring rather than a one-time bounty, your earnings compound as your referrals stick around.How is recurring commission different from a one-time referral fee?Most referral programs pay a single one-time bounty. The Jamdesk affiliate program pays 30% of every payment your referral makes, every month, for as long as they stay a customer — so one good referral can keep earning for years, not just once.How does the 60-day attribution window work?The program uses a 60-day attribution window: when someone uses your referral link, a paid Jamdesk signup within 60 days counts as your referral — even if they don't sign up on their first visit.Who can join the Jamdesk affiliate program?Bloggers, YouTubers, newsletter writers, course creators, agencies, and anyone with an audience of developers or technical writers. If your audience would benefit from better documentation, you're a good fit.Do I need to be a Jamdesk customer to join?No. Anyone with a relevant audience can apply, whether or not you currently use Jamdesk yourself.How and when do I get paid?We'll confirm payout details — schedule, threshold, and method — when your application is approved. This page registers your interest so our team can reach out with next steps. ## Apply to the affiliate program Tell us where you'll share Jamdesk and we'll get you set up. No fees, no commitment. WebsiteFull nameEmailWebsite or audience URLApply to join Final program terms are confirmed on approval and subject to our affiliate agreement. --- ## AI Score — Is Your Documentation Agent-Ready? URL: https://www.jamdesk.com/ai-score # Can AI agents read your docs? Get an instant agent-readiness score for any documentation site — graded against the open AFDocs standard. Get AI Score Free · No sign-up · Checks llms.txt, markdown, structure & more Or install the Chrome extension to run on any page ## What you'll get A 0–100 score and letter grade, a category-by-category breakdown, and the specific checks to fix next. Here's a real result for docs.stripe.com. ## What is an AI Score? An AI Score measures how easily AI agents, assistants, and LLMs can read and use your documentation. AI tools increasingly answer questions and complete tasks by reading docs directly — but most documentation is built for human readers, with layouts, scripts, and navigation that machines can't parse. The result: agents miss content your readers can see. The AI Score grades any site from 0 to 100 against the open AFDocs standard, so you can see exactly where agents succeed and where they get stuck — and what to fix first. ## What the AI Score checks The score is based on the open AFDocs standard — the things that make documentation readable by machines. ### llms.txt Does the site publish an llms.txt index — a sitemap for AI agents? It's the single highest-impact signal of agent-readiness. ### Markdown access Can each page be fetched as clean Markdown? Agents parse Markdown far more reliably than rendered HTML full of scripts and layout. ### Content discoverability Is real content near the top of the page, with meaningful headings — or buried below heroes, callouts, and navigation? ### Page size Are pages small enough to fit an agent's context window? Oversized pages get truncated, and the agent never sees the end. ### URL stability Are links durable and predictable, with proper redirects for moved pages instead of dead ends and 404s? ### Reachability Can an agent actually load the pages? Login walls and bot blocks keep AI tools out — and keep your docs out of their answers. ## How it works 1 ### Paste a URL Enter any public documentation site — your own or a competitor's. No sign-up, no install. 2 ### Run a fast scan We check the page against the open AFDocs standard in a few seconds and grade it from 0 to 100. 3 ### See what to fix Get a letter grade and a breakdown of exactly which checks pass and which to improve next. ## AI Score FAQ What is an AI Score?An AI Score is a 0–100 rating of how easily AI agents, assistants, and LLMs can read and use a documentation site. AI tools increasingly answer questions by reading docs directly, but most sites are built for human readers — so machines miss content people can see. The score grades a site against the open AFDocs standard and shows exactly which checks pass and which need work.What is AFDocs?AFDocs is an open standard (afdocs.dev) for documentation that AI agents can read reliably. It defines concrete, testable checks — publishing an llms.txt index, serving pages as clean Markdown, keeping pages within agent context limits, using stable URLs, and more. The AI Score runs the AFDocs checks against your site and turns the results into a single grade.What is llms.txt?llms.txt is a plain-text file at the root of a site that lists its documentation in a form AI agents can read quickly — a kind of sitemap for LLMs. It's one of the highest-impact things you can add for agent-readiness, and one of the first things the AI Score checks for.Is the AI Score free?Yes. You can score any public documentation site for free, with no sign-up required. Enter a URL and get an instant grade plus a breakdown of what to fix.How is the AI Score calculated?The tool runs a fast scan of the page you submit against the AFDocs checks, groups the results into categories — such as content discoverability, Markdown access, page size, and URL stability — and combines them into a 0–100 score and letter grade. It's a quick estimate based on a single page; a full build-time scan covers your whole site.How do I improve my documentation's AI Score?Start with the failing checks in your breakdown: publish an llms.txt index, make sure each page is available as clean Markdown, keep pages small enough to fit agent context windows, put real content near the top of each page, and use stable URLs with proper redirects. Docs built on Jamdesk pass most of these by default — llms.txt, Markdown export, and clean structure are generated automatically on every build.Does the AI Score work for any website?It's designed for documentation sites — product docs, API references, knowledge bases, and guides. You can point it at any public http(s) URL, but the checks and guidance assume documentation content. Pages behind a login can't be read by agents, so they score low by design.What happens to the URL I submit?The URL of the page you choose to score is sent to Jamdesk's servers to run the scan, and is cached briefly (about 15 minutes) so repeat checks are fast. We don't track your browsing or store page contents. See the Jamdesk privacy policy for details. Chrome extension ## Score any site from your toolbar Add the free Jamdesk AI Score extension and grade any documentation site as you browse — one click, no copy-paste. It only runs when you click. Add to Chrome ## Build docs that score well by default Jamdesk generates llms.txt, Markdown export, and clean structure on every build — so your documentation is agent-ready out of the box, no checklist required. It also scores your docs against this same standard on every build, so you catch regressions the moment they ship. See how AI Score works in Jamdesk → Start free trial See how the major docs platforms scored in our agent-readiness benchmark. --- # Blog Posts ## Halo: A Warmer Theme for Docs URL: https://www.jamdesk.com/blog/halo-docs-theme Published: 2026-08-04 *Halo is our fourth built-in docs theme: warm sand ground, caramel accent, Figtree, and a rounded content card the writing sits on. Switching is one line in docs.json.* Halo is live. It's the fourth beautiful built-in theme in Jamdesk, and you turn it on by changing one line of your `docs.json`. Sand background, caramel accent, Figtree, and corners rounded far past what the other three do. It excels as a guide that is conducive to longer text passages, like onboarding, concepts, tutorials, the long "how this actually works" page. You can see it running at [halo.jamdesk.com](https://halo.jamdesk.com/?ref=cms.jamdesk.com) before you commit to anything. ## The Content Sits in a Card The palette is the part you notice first, but it is just a part of what makes Halo distinct. Your body content sits on a card. The header and left nav sit _outside_ it, on a darker ground. The content seems lifted while the navigation stays out of the way. ![](https://cms.jamdesk.com/content/images/2026/08/image.png) | Region | Light mode | | --- | --- | | Ground (header and nav sit here) | `#F7F2E8` (sand) | | Content card | `#FFFDF9` (warm white) | | `` components on top | one step back down | The card rounds on its left corners and runs flush off the right edge, so it reads as a surface rather than a floating box. It stops just short of the bottom of the viewport, which is what makes the bottom-left corner visible. The table of contents lives inside the card with the body. Dark mode inverts the colors: warm black ground at `#120F0C`, card at `#1A1613`. ![](https://cms.jamdesk.com/content/images/2026/08/image-1.png) ## No Shadows Although our first pass at the design gave Halo soft warm-tinted elevation, we shipped it flat instead. Stacking drop shadows onto surfaces that already carry 1px borders and dividers introduces too much visual friction and muddiness. The card was already getting its lift from the background. Every shadow token in Halo is `none`, in both modes. ## Turning It On One line: ```json { "$schema": "https://www.jamdesk.com/docs.json", "theme": "halo", "name": "My Docs" } ``` Push, and your next build renders in Halo. No component changes, no CSS to write, no migration. If you don't like it, change the line back. Every other field in [the docs.json reference](https://jamdesk.com/docs/config/docs-json-reference?ref=cms.jamdesk.com) works the same across all four themes. Brand color still wins where you set it. Halo's caramel is a default, not a lock-in: ```json { "theme": "halo", "colors": { "primary": "#7C3AED" } } ``` That override replaces the accent across links, active nav items, and buttons while the sand ground, the card, and the radii stay put. Full options in the [theming docs](https://jamdesk.com/docs/customization/theming?ref=cms.jamdesk.com). ## When to Pick a Different One Halo is not the right default for every project, and we'd rather you switch once than switch twice. Reach for Pulsar if your docs are a dense API reference: endpoint after endpoint, heavy on tables and code blocks. Pulsar is dark-first and tight. Reach for Nebula if you want warm but sharp. It's cream and orange with square corners and IBM Plex Mono throughout, which gives it an editorial vibe while Halo is much more friendly. Jam stays the default for a reason. It is neutral, blue, and familiar, and it disappears behind your content, which is usually what you want documentation to do. Side-by-side previews of all four are in [the theming reference](https://jamdesk.com/docs/customization/theming?ref=cms.jamdesk.com), and every one of them is a one-line change to try. ## Try It on Your Own Docs Open your `docs.json`, set `"theme": "halo"`, and look at your own writing in it. A demo site tells you about the theme; your content tells you whether it fits. Ten seconds to switch, ten seconds to switch back. If you're not on Jamdesk yet, [start a free trial](https://dashboard.jamdesk.com/?ref=cms.jamdesk.com) and pick Halo in the editor. --- ## MCP vs API: The Difference for Developers URL: https://www.jamdesk.com/blog/mcp-vs-api Published: 2026-08-03 *A customer contacted us last month about their Jamdesk docs. Their team had switched to Claude Code, and Claude couldn't answer a single question about their own API. The docs were public and the search endpoint worked, but Claude just didn't know either of those things existed unless their specifically gave the docs URL at the start of every session. We told them to add our MCP server to Claude Code's config. Two minutes later Claude was searching their docs and giving back results. That gap,* A customer contacted us last month about their Jamdesk docs. Their team had switched to Claude Code, and Claude couldn't answer a single question about their own API. The docs were public and the search endpoint worked, but Claude just didn't know either of those things existed unless their specifically gave the docs URL at the start of every session. We told them to add our MCP server to Claude Code's config. Two minutes later Claude was searching their docs and giving back results. That gap, between "the API exists" and "the LLM can use it", is what MCP closes. MCP servers are wrappers around APIs, telling an LLM how to call them. ## What an API is An API is a contract between two pieces of software. REST, GraphQL, and gRPC are all APIs, and they primarily differ on the shape of the contract. (We wrote a longer primer on [what an API is](https://www.jamdesk.com/blog/what-is-an-api?ref=cms.jamdesk.com).) Traditionally, an API was built for humans, though that has changed with AI. A developer read your reference docs, picked an endpoint, and constructed a request. Jamdesk's [docs search API](https://jamdesk.com/docs/jamdesk-api/search?ref=cms.jamdesk.com) is an example: ```bash curl -X POST "https://acme.jamdesk.app/_api/search" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"query": "How do I authenticate?", "limit": 5}' ``` ```json { "results": [ { "title": "Authentication", "section": "API", "slug": "api/authentication", "content": "Every request needs a Bearer token. Generate one in Settings...", "url": "https://acme.jamdesk.app/api/authentication", "score": 0.95 } ], "query": "How do I authenticate?", "language": "en", "total": 1, "durationMs": 72 } ``` Back comes a stateless JSON response, readable by a human, with the definition living in your API docs or your OpenAPI spec. But wait, can't an AI agent just build against that API? It can, and we'll come back in a minute. ## What MCP is MCP, the [Model Context Protocol](https://modelcontextprotocol.io/?ref=cms.jamdesk.com), lets an LLM use your software without a human writing the client code. [Anthropic introduced it in November 2024](https://www.anthropic.com/news/model-context-protocol?ref=cms.jamdesk.com). OpenAI, Google, and most major IDEs and agent frameworks have adopted it since. Your server exposes three kinds of primitives: * **Tools** are executable functions the LLM can call (the `searchDocs` below). * **Resources** are read-only data the LLM can pull into context: files, database records, whole doc pages. * **Prompts** are reusable templates your server offers, like saved recipes the LLM can invoke. The LLM's host (Claude Desktop, Cursor, Claude Code, whatever) connects to your server, asks it some version of "what can you do?", and gets back a machine-readable menu that the model then reasons about in the middle of a conversation with a human who has never read your docs. Underneath it's [JSON-RPC 2.0](https://www.jsonrpc.org/?ref=cms.jamdesk.com) over either stdio (local) or Streamable HTTP (remote). The same docs search, via MCP: ```json { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "searchDocs", "arguments": { "query": "How do I authenticate?", "limit": 5 } } } ``` This looks like a REST call, right? Structurally it is one. What's different sits upstream of the payload. ## What an MCP server looks like An MCP server is mostly a wrapper around an API you already shipped. It doesn't replace your backend, and no part of it talks to a model. It sits in front of endpoints that already exist and describes them in terms a model can act on. Two handlers do the real work. The `ListTools` handler answers the "what can you do?" question from the last section by giving back the menu of available tools. The `CallTool` handler answers `tools/call`, taking the arguments the model composed, doing the work, and returning text. Everything else in the file is setup. Here it is wrapping the Jamdesk search API, in about fifty lines of TypeScript with the [official SDK](https://github.com/modelcontextprotocol/typescript-sdk?ref=cms.jamdesk.com): ```typescript import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; const server = new Server( { name: "docs", version: "1.0.0" }, { capabilities: { tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [{ name: "searchDocs", description: "Search the documentation for relevant pages, API references, " + "and guides. Returns results ranked by relevance. Use this before " + "getPage when you don't know the exact page path.", inputSchema: { type: "object", properties: { query: { type: "string" }, limit: { type: "number" } }, required: ["query"], }, }], })); server.setRequestHandler(CallToolRequestSchema, async (req) => { // The registry is your product surface: reject anything not in it. if (req.params.name !== "searchDocs") { throw new Error(`Unknown tool: ${req.params.name}`); } const { query, limit = 5 } = req.params.arguments as { query: string; limit?: number; }; const res = await fetch("https://acme.jamdesk.app/_api/search", { method: "POST", headers: { Authorization: `Bearer ${process.env.TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ query, limit }), }); if (!res.ok) throw new Error(`Search failed: ${res.status}`); return { content: [{ type: "text", text: JSON.stringify(await res.json()) }] }; }); await server.connect(new StdioServerTransport()); ``` You just need to register the tools, handle the call by hitting the REST API you already have, and return the text. Notice how little of it is about AI. It's plumbing around a `fetch` to a backend that already existed, and the most product-critical line in the whole file is a `description` string. For more info, see the [official quickstart](https://modelcontextprotocol.io/quickstart/server?ref=cms.jamdesk.com) guide. ## The core differences | | REST API | MCP | | --- | --- | --- | | **Consumer** | Human developers | LLMs and agents | | **Discovery** | A developer reads your docs | The client calls `tools/list` at runtime | | **The contract** | URL, params, and your reference docs | Tool name, description, and JSON Schema | | **Protocol** | HTTP + JSON | JSON-RPC 2.0 over stdio or Streamable HTTP | Discovery is the big one. With an API, the developer is the discovery mechanism. With MCP, the model is, at runtime: ```json { "jsonrpc": "2.0", "id": 2, "method": "tools/list" } ``` ```json { "result": { "tools": [ { "name": "searchDocs", "description": "Search the documentation for relevant pages, API references, and guides. Returns up to 50 results ranked by relevance.", "inputSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "The search query (e.g., \"authentication\")" }, "limit": { "type": "number", "description": "Maximum number of results (default: 10, max: 50)" }, "type": { "type": "string", "enum": ["all", "api", "guide", "quickstart", "help", "component"] } }, "required": ["query"] } }, { "name": "getPage", "description": "Get the full content of a specific documentation page by its URL path.", "inputSchema": { "type": "object", "properties": { "slug": { "type": "string", "description": "The page path (e.g., \"api/authentication\")" } }, "required": ["slug"] } } ] } } ``` ![The two tools a model discovers at runtime from the Jamdesk docs MCP server: searchDocs and getPage, each with its description and input schema](https://cms.jamdesk.com/content/images/2026/07/mcp-vs-api-img-2-tools-list-light-2.png) The real `tools/list` response from our docs server. Two tools, and those two sentences plus a handful of field descriptions are the only documentation the model ever reads. The `inputSchema` tells a model _how_ to call the tool. The `description` decides _whether_ it calls at all. That second job is the one that fails quietly. When a description is vague, nothing throws and nothing lands in your logs, because the call you wanted was never made. The model read your sentence, decided this wasn't the tool it needed, and did something else instead: reached for another tool, guessed at a URL, or answered from memory. The user gets a worse answer and never learns a better one was available. ## The state question just changed Plenty of blog posts will tell you that MCP is stateful and REST is not. That was always too strong, and now it's wrong. The session was real but optional. An MCP session opened with an `initialize` handshake, client and server negotiated capabilities and a `protocolVersion`, and the session could stay open so follow-up calls skipped re-auth and re-discovery. Servers were free to skip all that and run stateless over Streamable HTTP. Ours does. That option is now gone. The [2026-07-28 revision](https://blog.modelcontextprotocol.io/posts/2026-07-28/?ref=cms.jamdesk.com) removed the `initialize` handshake and the `Mcp-Session-Id` header outright. The core is stateless. Any request can land on any server instance, so the sticky routing and shared session stores that horizontal deployments used are gone at the protocol layer. Long-running work moved to a Tasks extension, where a `tools/call` hands back a task handle the client polls. The revision shipped on **July 28, 2026**. If you're writing a server now, write it stateless to save yourself a migration. ## Side by side: same task, both protocols Fetching one specific docs page. Both of these work right now, against our own live docs. **REST:** ```bash curl "https://jamdesk.com/docs/ai/mcp-server.md" ``` A developer wrote that. They knew the `.md` suffix works on Jamdesk because they read the docs. **MCP:** ```json { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "getPage", "arguments": { "slug": "ai/mcp-server" } } } ``` A user typed "how do I set up the MCP server?" into Claude Code, Claude read `getPage` out of `tools/list`, and inferred the argument from the conversation and the schema. The response comes back as a `content` array the model reads directly. Same functionality. What differs is who composed the call, and how they knew what to put in it. ## But can't an agent just call my API? Yes. Point a coding agent at your OpenAPI spec and it will write you a client, and for a one-off job that is usually the right answer. The difference is who does the setup, and how many times. With a REST API, somebody finds the docs, configures credentials, and writes the glue, and then somebody does it again for the next tool and the next user. An MCP server does that work once, on your side, and every client that connects inherits it. Same endpoints, same backend. What changes is that discovery happens at runtime instead of in someone's editor. ## When to use which **Ship a REST or GraphQL API when:** * Your frontend, mobile app, or customer SDKs consume the data. * Callers are deterministic software that already knows what it wants. * You need broad ecosystem compatibility (Postman, curl, every HTTP client ever written). **Ship an MCP server when:** * Your users want to work with your product through an AI assistant. * Your capabilities would earn their place inside someone else's agent workflow. * You want to be callable without customers writing an SDK first. **Ship both when** you have a real product. The REST API does the work. The MCP server exposes a thoughtful subset to LLMs, with descriptions tuned for a model rather than a human. They read from the same backend. We see one mistake more than any other: teams treat MCP as a replacement for their API and expose every endpoint as a tool. Don't do that. We've watched models get noticeably worse at picking the right tool as the registry grows, and a model staring at 200 of them is a model that guesses. Expose the handful of operations that match how users actually phrase requests. **Already have an OpenAPI spec?** Open-source generators ([snaggle-ai](https://github.com/snaggle-ai/openapi-mcp-server?ref=cms.jamdesk.com) and [janwilmake](https://github.com/janwilmake/openapi-mcp-server?ref=cms.jamdesk.com) both ship one) will convert it into a runnable MCP server, one tool per endpoint. Ship that first. Then rewrite the descriptions of the few tools that matter, by hand, and delete most of the rest. Generated descriptions are technically correct and useless. They describe the endpoint, not the job the user is trying to do. One gotcha is the model can only paginate if you let it. If your tool wraps an endpoint that returns the first hundred rows and your schema exposes no cursor or offset, the model has no way to ask for row 101, and it will rarely think to mention that the answer was truncated. Our own `searchDocs` takes a `limit` and no offset, which is fine for docs search and would be a bug on a transactions API. ## How we do it at Jamdesk We build [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com), a documentation platform for software teams. Every docs site gets a REST search API at [`/_api/search`](https://jamdesk.com/docs/jamdesk-api/search?ref=cms.jamdesk.com) and a built-in MCP server at [`/_mcp`](https://jamdesk.com/docs/ai/mcp-server?ref=cms.jamdesk.com). A customer with docs at `acme.jamdesk.app` runs one command: ```bash claude mcp add --transport http acme-docs https://acme.jamdesk.app/_mcp ``` ![A live MCP tools/call against the public Jamdesk docs server returning three ranked results for the query How do I add a custom domain](https://cms.jamdesk.com/content/images/2026/07/mcp-vs-api-img-1-live-call-light-2.png) A real call against our own public docs server, reproducible as printed. No API key, no client code: the model asked, and the docs answered. And Claude Code can search and read Acme's documentation directly. Our REST endpoint needs an API key and exists for code your team writes, while the MCP server answers the model directly and needs no key at all. We expose two tools: `searchDocs` and `getPage`. Most of our REST endpoints exist for humans building integrations, and only two operations are useful to an agent answering a question. The hardest part of shipping MCP wasn't the protocol. It was the descriptions. "Search the docs" wasn't enough: Claude would skip the tool and guess a URL instead. What ships today spells out what gets searched and what comes back: "Search the documentation for relevant pages, API references, and guides. Returns up to 50 results ranked by relevance." ![The same tool with a vague description versus a specific one, and how the model behaves differently in each case](https://cms.jamdesk.com/content/images/2026/07/mcp-vs-api-img-3-description-light-2.png) The code is identical in both cases. The only thing that changed is the sentence the model reads. `getPage` needed the same treatment, one level down. It takes a slug like `api/authentication`, not a full URL, and spelling that out in the _field_ description is what stopped models from confidently passing `https://acme.jamdesk.app/api/authentication` and getting nothing back. Field descriptions are part of the contract too. Writing for a model is still writing. We went deeper on that in [how AI-friendly docs platforms actually are](https://www.jamdesk.com/blog/ai-friendly-docs-platforms-scored?ref=cms.jamdesk.com). ## Summary APIs are how software talks to software. MCP is how software talks to LLMs. If developers use your product, you need an API. If you want your product usable inside an AI assistant without customers writing glue code, you need an MCP server too. Our own docs run on [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com), so their [MCP server](https://jamdesk.com/docs/ai/mcp-server?ref=cms.jamdesk.com) is public. Paste this into a terminal and ask Claude Code something about Jamdesk: ```bash claude mcp add --transport http jamdesk-docs https://jamdesk.com/docs/_mcp ``` --- ## Designing Docs for AI Agents URL: https://www.jamdesk.com/blog/designing-docs-for-ai-agents Published: 2026-07-22 *Your docs' fastest-growing reader doesn't have eyes. What changes when documentation gets consumed by agents: serve markdown, write everything down, make every page stand alone, and treat errors as content.* Last week, Ben Swerdlow at Freestyle published [Designing APIs for Agents](https://www.freestyle.sh/blog/opinion/designing-apis-for-agents?ref=cms.jamdesk.com), arguing that the API design rules we spent twenty years learning are backwards for AI agents. Agents read everything, so explicitness beats convenience, and precise errors beat forgiving defaults. He's right, and the same inversion has already hit documentation. Most docs teams are just coming to realize this. We run a [docs platform](https://jamdesk.com/?ref=cms.jamdesk.com), so we know a few things about docs. Here's what's we've learned: write everything down, make every page stand alone, serve markdown instead of chrome, and treat your error messages as first-class content. ## Your Reader are Now AI Agents Documentation traffic is shifting from people to machines, fast. From May 2024 to May 2025, AI and search crawler traffic grew 18%, with OpenAI's GPTBot alone up 305% ([Cloudflare](https://blog.cloudflare.com/from-googlebot-to-gptbot-whos-crawling-your-site-in-2025/?ref=cms.jamdesk.com), 2025). Need more convincing? In July 2025, Anthropic's crawlers fetched about 38,000 pages for every one human visitor they referred back; OpenAI's ratio was around 1,100 to one ([Cloudflare](https://blog.cloudflare.com/crawlers-click-ai-bots-training/?ref=cms.jamdesk.com), 2025). Machines now read orders of magnitude more of your documentation than people do. Meanwhile the humans moved to asking chat/AI agents instead of their own research. By 2025, Stack Overflow was receiving about as few questions per month as it did in 2009, the year it launched ([The Pragmatic Engineer](https://blog.pragmaticengineer.com/stack-overflow-is-almost-dead/?ref=cms.jamdesk.com), 2025). Did the developers stop having questions? Nope, they started asking assistants, and the assistants ask your docs. So the question isn't whether to design docs for agents. Agents are already your highest-volume audience. The question is whether they can use what they find. ## The Playbook We All Learned Good docs for humans follow certain rules, which can be summarized as "[Don't make me think](https://www.amazon.com/dp/0321965515?ref=cms.jamdesk.com)". For example, start with a quickstart guide, everyone loves help videos, and hide the complex flags until the reader needs them. You also want to have everything well organized in a side nav so I can quickly find what I'm looking for. Every one of those rules exists because human attention is scarce. Your users are busy, get bored in minutes, and leave the moment they feel lost (or assume this isn't what they are looking for). Traditionally, yours docs serve two purposes: technical/informational data and marketing. The former is self-evident, but marketing you might have not considered. We wrote a whole post on [writing documentation developers actually read](https://www.jamdesk.com/blog/how-to-write-documentation-that-developers-actually-read?ref=cms.jamdesk.com), and if you compress it to one idea, it's attention management: respect the reader's time, surface the likely next step, get out of the way. Design for the reader's scarcest resource, in other words. For humans, that's attention. ## Agents Break Every Assumption An agent's scarce resource is context tokens: what it can afford to fetch and hold while answering. Attention never enters into it. ![A person reaches an answer through search, navigation, and scrolling, while an agent fetches llms.txt and then a single markdown page](https://cms.jamdesk.com/content/images/2026/07/img-2-two-readers-2.webp) When agents arrive at your site, they aren't navigating, click though your sidebar or typing in your search box, they are fetching. An agent lands on one URL, cold, and either finds the answer there or fetches again. Agents read everything you give them, instantly. Swerdlow's phrase for APIs was "agents can read our entire docs in one sitting." Hiding complexity from them doesn't reduce confusion as it does for people. And agents arrive opinionated. Their training data contains your 2025 docs, your deprecated auth flow, your old parameter names. Live documentation is the correction mechanism for those stale priors. If the current truth isn't written down and fetchable, the agent uses the old version. One caution before you swing the other way: reading everything isn't free. In July 2025, Chroma tested 18 frontier models and found every single one degraded as input length grew, a failure mode they named context rot ([Chroma Research](https://research.trychroma.com/context-rot?ref=cms.jamdesk.com), 2025), so don't make one giant page of all your docs. ## Use Your Words Give agents the words without the website by proving them with markdown (md file). We measured our own quickstart both ways, and you can rerun this today: ```bash $ curl -sLo /dev/null -w "%{size_download} bytes\n" https://jamdesk.com/docs/quickstart 225527 bytes $ curl -sLo /dev/null -w "%{size_download} bytes\n" https://jamdesk.com/docs/quickstart.md 7246 bytes ``` That is 31x fewer bytes, and another example is Vercel ran the same test on their own pages in 2026 and measured [500 KB of HTML against 3 KB of markdown](https://vercel.com/blog/making-agent-friendly-pages-with-content-negotiation?ref=cms.jamdesk.com). All that extra load (218 K) are scripts, styles, nav, and hydration payload - what makes the web so pretty. But agents don't need or want this, since they will spend tokens downloading it all and then throw it away. ![The same docs page served as HTML is 225,527 bytes but only 7,246 bytes as markdown, a 31x difference](https://cms.jamdesk.com/content/images/2026/07/img-1-html-vs-md-2.webp) _Measured 2026-07-16. Both URLs are live if you want to check our math._ And to really hammer the point home, [we scored seven docs platforms for AI-friendliness](https://www.jamdesk.com/blog/ai-friendly-docs-platforms-scored?ref=cms.jamdesk.com) and one served 1,049,919 bytes of HTML containing 1,279 bytes of text because the content only existed after JavaScript ran. To a crawler doing plain HTTP, those docs are a loading spinner. The fix is a `.md` markdown mirror of every page. You create the same URL plus `.md`, plain markdown. [Stripe ships this](https://docs.stripe.com/llms.txt?ref=cms.jamdesk.com) across their entire docs site. [So do we](https://jamdesk.com/docs/ai/markdown-source?ref=cms.jamdesk.com), on every Jamdesk site, automatically. Server-render your HTML too. But give agents the door that doesn't cost 31x. ## Be Explicit Swerdlow's harshest API rule is "defaults are bad" and the magic that helps humans makes agents guess. The docs equivalent is implicit knowledge is bad, [explicit knowledge is good](https://www.merriam-webster.com/grammar/usage-of-explicit-vs-implicit?ref=cms.jamdesk.com). What do I mean by this? Remember, the AI agent might only be fetching a single page or even just a section of it. So you don't want to make the AI have to guess, assume, or have to figure out contradictions. For example: * **No relative references.** "As mentioned above" and "see the previous section" are dead weight to an agent who fetched one page. Link to the actual page instead. Also, this is a good SEO practice. * **Full context per page.** Restate which product, which version, which API. The agent may have fetched nothing else. * **One name per concept.** If the same thing is a "project" on one page, a "site" on another, and a "workspace" in the dashboard, an agent treats them as three things. Swerdlow calls this staying in distribution. Tech writers call it terminology discipline and consider it a best practice. * **And date things.** "As of the 2026-07-28 protocol revision..." lets an agent weigh your page against what it half-remembers from training. ## Errors Are Documentation An agent debugs by searching fop the error. If it hits a failure, the agent does a search with the error message as a query string. Pretty sweet if your docs are the result! A good idea is to document the error path with the same priority as your tutorials. A page per error, or a catalog, with the verbatim message as the heading: ```markdown ## Error: `DNS_VERIFICATION_FAILED` **What it means:** We couldn't find the TXT record proving you own this domain. **Why it happens:** The record hasn't propagated (wait up to 48h), or it was added to the wrong zone (check the apex, not the subdomain). **Fix:** `dig TXT _jamdesk-verify.yourdomain.com` should return your token. If it doesn't, re-add the record from Settings → Domains → Verify. ``` As Swerdlow put it for APIs: errors are one of the best surfaces an agent has for finding the happy path. Your docs are where that surface lives. ## Examples are Important For human readers, a code sample is a teaching aid. For agents, it's a template that gets instantiated verbatim, at scale. Agents pattern-match against examples more strongly than against prose, which means a subtly wrong sample has a large impact. Some good guidelines on examples for AI agents: * **Runnable as printed.** Real endpoints, real field names, no `` inside strings that look copy-pasteable. * **Complete.** Include the imports, the auth header, the response shape. An agent won't infer the missing 20% the way a senior dev would; it will invent it. * **Current.** A deprecated example is worse than no example, because it's _evidence_ for the stale behavior the agent already believes. ## The Discovery Stack: llms.txt, .md, MCP Everything above assumes the agent found the right page. That's the job of three pieces of infrastructure, one of which is genuinely controversial. ![The agent-readable docs stack: llms.txt as the index, per-page markdown endpoints as the content, and an MCP server as the query interface](https://cms.jamdesk.com/content/images/2026/07/img-3-discovery-stack-2.webp) _Three entry points into the same content._ **`llms.txt`** is a markdown index at your site root: what exists, where, one fetch. By May 2026, 36,120 sites published one, up 8.8x in a year ([PPC Land](https://ppc.land/llms-txt-adoption-rises-8-8x-but-97-of-files-get-zero-ai-requests/?ref=cms.jamdesk.com), 2026). But do the AI agents read the llms.txt file? In June 2026, [Ahrefs measured 97% of those files receiving zero requests](https://ahrefs.com/blog/what-is-llms-txt/?ref=cms.jamdesk.com) in a month. Google's John Mueller had [compared the file to the keywords meta tag](https://www.searchenginejournal.com/google-says-llms-txt-comparable-to-keywords-meta-tag/544804/?ref=cms.jamdesk.com) a year earlier (2025), and [defenders](https://searchengineland.com/no-llms-txt-is-not-the-new-meta-keywords-458199?ref=cms.jamdesk.com) have argued with him since. Our take: Mueller is right about background crawlers and wrong about what else matters. Agentic fetchers (a Claude Code session, a Cursor index, anything told to go read the docs) use it as a map when it exists, because it's the cheapest possible answer to "what pages should I fetch?" [Stripe ships one](https://docs.stripe.com/llms.txt?ref=cms.jamdesk.com) with instructions for LLM agents embedded in it. When it's [auto-generated from your nav](https://jamdesk.com/docs/ai/llms-txt?ref=cms.jamdesk.com), like ours, the cost is zero. Zero-cost insurance doesn't need a consensus. **Per-page `.md` endpoints**. As discussed above (oops, we shouldn't be doing this), the token and speed savings are measurable. **An MCP server** turns your docs from pages into tools: `searchDocs`, `getPage`. Every Jamdesk site [exposes one at `/_mcp`](https://jamdesk.com/docs/ai/mcp-server?ref=cms.jamdesk.com), no key required. One command makes any of our customers' docs readable from inside Claude Code: ```bash claude mcp add --transport http jamdesk-docs https://jamdesk.com/docs/_mcp ``` One last trick: put instructions for agents _inside the content_, where every reader lands. The top of our own quickstart reads: ```markdown > **For AI agents:** the complete documentation index is at [llms.txt](/docs/llms.txt). > Append `.md` to any page URL for its markdown version. ``` Any agent that lands on any page now knows about both entry points. ## Summary Your docs were already [your most important marketing channel](https://www.jamdesk.com/blog/api-docs-marketing-tool?ref=cms.jamdesk.com) back when only humans read them. Now they're your interface to every AI assistant your users work inside, so you should focus on making them the most AI-friendly docs possible. We also built [AI Score](https://jamdesk.com/docs/ai/ai-score?ref=cms.jamdesk.com) to automate exactly this audit, and [scored seven platforms with it](https://www.jamdesk.com/blog/ai-friendly-docs-platforms-scored?ref=cms.jamdesk.com) if you want a baseline. Or, if you'd rather let someone else do it for you, every Jamdesk site comes with the whole stack by default: `.md` endpoints, `llms.txt`, `llms-full.txt`, and an MCP server, generated from the docs you already have. [Deploy one in five minutes](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com), then curl your own quickstart with `.md` on the end. --- ## Introducing the Jamdesk Visual Web Editor URL: https://www.jamdesk.com/blog/introducing-the-jamdesk-visual-web-editor Published: 2026-07-16 *Edit your Jamdesk docs directly in the browser. A three-pane editor with live preview, page templates, and commits straight to GitHub, with no local setup or terminal required.* Sometimes you just want to make a quick change to your docs. Or you want to see how your change looks without using any additional tooling beyond the browser. Well now you can with the Jamdesk visual web editor. And best of all, it is included on every plan at no extra charge. You can now edit your documentation directly in the dashboard with the web editor. There is no need to worry about a git clone, installing package, or opening a terminal. The easiest way to get started is to just open the [editor on your project](https://dashboard.jamdesk.com/?ref=cms.jamdesk.com) and start editing. Also, see our docs to learn even more about the [web editor](https://jamdesk.com/docs/development/web-editor?ref=cms.jamdesk.com). ![Jamdesk web editor](https://cms.jamdesk.com/content/images/2026/07/web-editor.webp) Jamdesk web editor ## How it works The editor gives you three panes that stay in sync. On the left sits your site navigation, read straight from `docs.json`, so the structure you edit is the structure your readers see. In the center is the MDX editor, with syntax highlighting and a running word count. On the right is a preview that re-renders as you type, showing the real page rather than a rough approximation. Your edits save as drafts in the browser, so you move between pages without losing work. Nothing goes live until you decide it should. When you want to check how a page holds up, the preview toggles between desktop and mobile, and between light and dark, so you catch a layout problem before your readers do. New pages follow the same short path. Choose "Add page," pick a template, and give it a title. The filename generates itself from that title, you assign the page to a navigation group, and it opens as a draft ready to write. You don't have to think too much about the file path or guess where the new entry belongs in the tree. ![Add a page in the web editor](https://cms.jamdesk.com/content/images/2026/07/add-page.webp) Add a page in the web editor ## Committing without collisions When the writing is ready, the commit dialog shows every file you changed. Write your own message, or select Generate and let it summarize the changes for you. The commit triggers the same build as a `git push`, so the browser workflow lands in exactly the same place as the local one. Teammates who work from an editor and teammates who work from the dashboard commit to the same repo, the same way. The editor also protects you from the classic overwrite. If someone pushed a change upstream while you were editing, a three-way merge surfaces it before you commit, so your work never quietly replaces theirs. You get the convenience of a browser editor with the version history and review trail you already rely on. ## Get Started Documentation goes stale when editing it is harder than ignoring it. The web editor drops that cost to near zero, for the developer fixing a typo between meetings and for the teammate who never touches Git at all. Every edit still becomes a commit with a build behind it, so nothing about your process changes except how many people are able to take part in it. To use it, you need a project connected to a GitHub repository and branch, and a desktop browser around 1400 pixels wide or more. All Jamdesk users get the editor as part of their plan. Open your project in the dashboard, find a page that needs a small fix, and make the edit right there. [Open the web editor](https://jamdesk.com/docs/development/web-editor?ref=cms.jamdesk.com). --- ## Why is Jamdesk better than Mintlify? URL: https://www.jamdesk.com/blog/why-jamdesk-is-better-than-mintlify Published: 2026-07-13 *Mintlify charges you to use the AI in your own docs. Jamdesk doesn't — here's the math, straight from Mintlify's own pricing.* For us it comes down to one thing: Mintlify charges you to use the AI in your own docs. We don't! Let's go over how Mintlify works and their AI pricing. First, Mintlify AI is based on a credit system, which, to our chagrin\*, is becoming more common with token based system. This means every AI usage costs a certain number of credits. For example, if a user initiates an AI Chat, that is 23 credits or if you fix something in your docs with AI that could be 241 credit. To gain entry past the AI red-velvet rope, you're required to be on the Mintlify Pro plan ($540 a month), which comes with 10,000 monthly credits. A single AI assistant answer at about 23 credits, so that's roughly 430 answers a month. If you need [more credits](https://www.mintlify.com/docs/credits?ref=cms.jamdesk.com), packs start at $145/month for another 25,000. And that 430 assumes chat is all you touch. Agent runs are ~115 credits each, and the automations that fix your docs for you eat 180 to 913 credits every time one fires: 330 to catch typos, 235 for a style review, 913 for a translation pass. Turn a few of those on watch either your credits go to zero or your bank account. In other words, the more your readers actually use your docs AI, the more you pay. That always struck us as backwards and complicated. Jamdesk is $29/month, flat. AI Chat, AI Analytics, AI Score, and AI Build Fixes (it auto-suggests a fix when a docs build breaks; I haven't found anything like it on Mintlify) are all just included. There are no credits to ration, no per-question overage, and no surprise end-of-month bill. To be fair to them, Mintlify's a genuinely good product. It's polished, it's everywhere, and the ecosystem is big. But if you're choosing a docs tool today and you'd rather lean on the AI than watch a meter, $29 flat versus $540-and-up metered is the difference worth weighing. That is one of the reasons that Jamdesk is better than Mintlify! And of course there is more on why Jamdesk is a great [Mintlify alternative](https://www.jamdesk.com/compare/mintlify-alternative?ref=cms.jamdesk.com). Happy to answer anything in the [comments](https://www.reddit.com/r/Jamdesk/comments/1udpibs/why_is_jamdesk_better_than_mintlify/?ref=cms.jamdesk.com). **\***Token tracking is so opaque and/or requires you to monitor the minutiae of your usage, well, it just makes it feel like a second job. That is why we said no for Jamdesk. We don't like this AI token/credit tracking, so we're not going to make our users do it. --- ## How to Generate an API Key URL: https://www.jamdesk.com/blog/how-to-generate-api-key Published: 2026-07-08 *Generate secure API keys the way Stripe does: a CSPRNG token, a type-and-environment prefix like sk_live_, and a SHA-256 hash you store instead of the raw key. Working code for generation, verification, revocation, and rotation in Node.js, Python, and Go.* Since we entered the agentic AI era, APIs and CLIs have been thrust into the zeitgeist. I've been seeing [Wall Street Journal articles](https://www.wsj.com/tech/ai/anthropic-claude-code-ai-7a46460e?ref=cms.jamdesk.com) mentioning both, which my nerd-self finds very cool. If you own a SaaS, it means it is important for you to consider offering an API/CLI, and if so, you need to make sure it is secure or you risk your entire business. GitGuardian found 28.6 million secrets exposed in public GitHub commits in 2025, a 34% jump year over year. Over 1.2 million of those were AI-service credentials alone, up 81% year over year ([GitGuardian State of Secrets Sprawl 2026](https://blog.gitguardian.com/the-state-of-secrets-sprawl-2026/?ref=cms.jamdesk.com)). Most had no prefix, no hashing, and no revocation path, and the key was just "my-voice-is-my-passport" — just kidding on that last one, Sneakers fans. To generate a secure API key, you use a cryptographically secure random number generator for 128 bits of randomness, add a type-and-environment prefix like `sk_live_`, and store only the SHA-256 hash. If you keep reading, we'll go over the full lifecycle with working code in Node.js, Python, and Go, using Stripe API keys as a blueprint. * Generate 128 bits of randomness from a CSPRNG * Add a type-and-environment prefix like `sk_live_` * Store only the SHA-256 hash, and show the key exactly once * Verify in four steps: format, hash, lookup, scope * Revoke instantly, and rotate with a grace period ## What Does a Good API Key Look Like? [Stripe's API keys](https://docs.stripe.com/keys?ref=cms.jamdesk.com) is one of the most widely recognized and copied formats around. In my previous API company we used this as a model for our API keys. Every key encodes three pieces of information before the random token even starts: ``` sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 │ │ │ │ │ └─ Random token (the secret) │ └─────── Environment (live or test) └────────── Type (sk = secret, pk = publishable) ``` This design is intentional, and I personally love it for the expressiveness and simplicity. When GitHub overhauled their own token formats, they added identifiable prefixes (`ghp_`, `gho_`, `ghs_`) for the same reason: the old hex-only tokens were "indistinguishable from other encoded data like SHA hashes" and nearly impossible for scanners to detect ([GitHub Engineering](https://github.blog/engineering/platform-security/behind-githubs-new-authentication-token-formats/?ref=cms.jamdesk.com)). The same convention plays out across every major API: | Provider | Format | Examples | What the Prefix Tells You | | --- | --- | --- | --- | | Stripe | `{type}_{env}_{token}` | `sk_live_`, `pk_test_`, `rk_live_` | Key type + environment | | GitHub | `{co}{type}_{token}` | `ghp_`, `gho_`, `ghs_` | Company + token type | | Twilio | `{type}{token}` | `SK` + 32 hex chars | Key type | | AWS | `{scope}{token}` | `AKIA`, `ASIA` | Permanent vs. session | The pattern: **a human-readable prefix, then cryptographically random bytes.** The examples below encode that token as hex, which is what `randomBytes` returns by default. Stripe's real keys use a longer base62 alphabet; if you copy their format exactly, widen the validation regex from `[0-9a-f]` to `[A-Za-z0-9]`. ### Publishable vs. Secret Keys Stripe splits keys into two categories because the trust boundary matters: * **`pk_live_` / `pk_test_` (publishable).** Safe to embed in frontend JavaScript. These keys can only create tokens (e.g., tokenize a credit card via Stripe.js). They can't read customer data, issue refunds, or make charges. * **`sk_live_` / `sk_test_` (secret).** Full API access. Server-side only. If this key leaks, an attacker can move money. Now, you may not have this situation and only have a back-end process or only front-end access. When you're designing your own API, ask: does this client need full access, or just enough to submit data? That answer determines whether to issue a `pk_` or `sk_` key. Whether you are back-end access only or front-end access only, you should still consider this pattern. For more on how APIs work under the hood, see our guide on [what an API actually is](https://www.jamdesk.com/blog/what-is-an-api?ref=cms.jamdesk.com). ## Step 1: Generate Cryptographically Random Bytes The entropy source matters more than anything else. Use your platform's CSPRNG (Cryptographically Secure Pseudorandom Number Generator — say that 3 times fast). Don't use `Math.random()` or `uuid.v4()`, and definitely not timestamps. **Node.js:** ```javascript import { randomBytes } from 'crypto'; const token = randomBytes(16).toString('hex'); // → "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" (32 hex chars, 128 bits) ``` **Python:** ```python import secrets token = secrets.token_hex(16) # → "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" ``` **Go:** ```go import ( "crypto/rand" "encoding/hex" "fmt" ) func generateToken() (string, error) { b := make([]byte, 16) if _, err := rand.Read(b); err != nil { return "", fmt.Errorf("CSPRNG failed: %w", err) } return hex.EncodeToString(b), nil // → "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" } ``` Sixteen bytes gives you 128 bits of entropy: 3.4 × 10³⁸ possible values. Brute-forcing that at a billion guesses per second would take 10²² years — unless the newfangled quantum computers become generally available, and then all bets are off. Why not UUIDs? A v4 UUID gives you 122 random bits, which is plenty of entropy, and `crypto.randomUUID()` is CSPRNG-backed, so randomness isn't the problem. Format control is: the fixed `8-4-4-4-12` shape leaks structure, can't carry a type-and-environment prefix, and forces dashes into your tokens. Raw `randomBytes` is the better fit when you want prefixes and a compact format. ## Step 2: Add Environment-Aware Prefixes You might — well, should — have at least two types of keys. One for your users' live site and one for the sandbox. If you don't have a sandbox yet, this is still a good practice since you may one day. With Stripe's `{type}_{environment}_` pattern every key becomes self-documenting and describes the environment: ```javascript import { randomBytes } from 'crypto'; function generateApiKey(type, environment) { const token = randomBytes(16).toString('hex'); return `${type}_${environment}_${token}`; } // Publishable keys — safe for client-side code generateApiKey('pk', 'live'); // → "pk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" generateApiKey('pk', 'test'); // → "pk_test_f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2" // Secret keys — server-side only, never expose generateApiKey('sk', 'live'); // → "sk_live_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d" generateApiKey('sk', 'test'); // → "sk_test_9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c" ``` Stripe also offers restricted keys (`rk_live_`, `rk_test_`) with scoped permissions. If your API needs granular access control, that is a third type you can add. Just register its prefix in the validation patterns (Step 4) and the Express middleware below, or every restricted key will fail the format check. The prefix is great because: 1. **Secret scanning.** GitHub, GitGuardian, and TruffleHog all match on known prefixes. A bare hex string flies under every scanner. A prefixed key triggers alerts within minutes of being pushed — especially if it is published on a public repo. 2. **Debugging speed.** When `pk_test_` appears in production logs, you know the client is misconfigured. Stripe gives some great error messaging if you try to use a live key in sandbox and vice versa. 3. **Cheap validation.** A regex check rejects malformed tokens before they touch your datastore. You can do this right in your middleware. More on this in Step 4. ## Step 3: Hash Before You Store One rule for all production systems: **never store the plaintext key.** Store its SHA-256 hash in your database. If you are in the EU (GDPR), want to be SOC 2 compliant, or get Enterprise clients, you'll be asked this. ```javascript import { createHash, randomBytes } from 'crypto'; function hashApiKey(rawKey) { return createHash('sha256').update(rawKey).digest('hex'); } // At generation time: const rawKey = generateApiKey('sk', 'live'); const hash = hashApiKey(rawKey); // Store `hash` in your database // Return `rawKey` to the user exactly ONCE console.log('Your API key (copy it now — you won\'t see it again):'); console.log(rawKey); // What gets saved to the database: // { id: "key_8f3a", hash: "7f83b1657ff1fc53...", prefix: "sk_live", last4: "c5d6", createdAt: 1713196800000 } ``` **Python equivalent:** ```python import hashlib def hash_api_key(raw_key: str) -> str: return hashlib.sha256(raw_key.encode()).hexdigest() ``` If you're thinking about using bcrypt, don't. API keys aren't passwords. They already carry 128 bits of entropy, so rainbow tables and dictionary attacks don't apply. SHA-256 is fast, deterministic, and produces a fixed 64-character hex digest that works well as a database lookup key. Bcrypt's intentional slowness would add latency to every API request for zero security gain. For one more line of defense, hash with **HMAC-SHA256 and a server-side pepper** instead of plain SHA-256. If your hash table ever leaks, plain digests are directly verifiable by anyone who can generate candidate keys; an HMAC pepper makes a stolen table useless without the secret: ```javascript import { createHmac } from 'crypto'; // PEPPER comes from your secret manager, never the database const hashApiKey = (rawKey) => createHmac('sha256', process.env.API_KEY_PEPPER).update(rawKey).digest('hex'); ``` Hash incoming tokens the same way at verify time and the rest of the flow is unchanged. Stripe, GitHub, and Twilio all follow this show-once pattern. If a user loses their key, they can't recover it and they must revoke and regenerate. A bit of user friction, but the right way for security. Store one non-secret hint alongside the hash: the prefix plus the last four characters (Stripe shows `sk_live_…c5d6`). You can't display the key again, so without that hint your dashboard can't tell two keys apart in a list. ![Stripe's API keys dashboard showing the prefix and last-4 hint for each key](https://cms.jamdesk.com/content/images/2026/06/stripe-keys-dashboard-2.webp) Long-lived secrets account for 60% of credential policy violations, according to GitGuardian's State of Secrets Sprawl 2026 report ([Help Net Security](https://www.helpnetsecurity.com/2026/04/14/gitguardian-ai-agents-credentials-leak/?ref=cms.jamdesk.com), 2026). Hashing is the cheapest mitigation you'll ever ship. ## Step 4: Verify Keys at Runtime When a request arrives with a [`Bearer` token](https://blog.postman.com/what-is-a-bearer-token/?ref=cms.jamdesk.com), run four checks in this order: 1. **Validate the format** (regex, no I/O) 2. **Hash the token** (SHA-256, CPU only) 3. **Look up the hash** (one DB or Redis read) 4. **Check scope** (project, environment, permissions) ```javascript import { createHash } from 'crypto'; const KEY_PATTERN = /^sk_(live|test)_[0-9a-f]{32}$/; async function verifyApiKey(rawKey, expectedProject) { // 1. Format gate — rejects garbage before any I/O if (!KEY_PATTERN.test(rawKey)) { return { ok: false, reason: 'invalid_format' }; } // 2. Hash the incoming token (~0.01ms, CPU only) const hash = createHash('sha256').update(rawKey).digest('hex'); // 3. Single O(1) lookup from Redis or your DB const record = await redis.get(`apikey:${hash}`); if (!record) { return { ok: false, reason: 'invalid_key' }; } // 4. Scope check — does this key belong to this project? const data = typeof record === 'string' ? JSON.parse(record) : record; if (data.projectId !== expectedProject) { return { ok: false, reason: 'wrong_project' }; } return { ok: true, id: data.id }; } ``` Notice the regex targets `^sk_`, not `^(pk|sk)_`. Narrow the pattern to the key type your endpoint expects, so a server-side search API should reject publishable keys and a client-side tokenization endpoint should reject secret keys. Be sure to use one regex per endpoint type. For high-throughput APIs, put the hash lookup in Redis rather than your primary database for faster in-memory lookups. The read is O(1) by hash, handles thousands of requests per second, and revocation is just a `DEL` on the key. I recommend treating Redis as a **cache, not the system of record**. I believe your DB should always be the system of record, and I've seen more than one Redis cache get unintentionally wiped. For example, if Redis runs an eviction policy like `allkeys-lru`, a still-valid key can be evicted and a paying customer gets a spurious `invalid_key`; on a cache miss, fall through to your database and repopulate, or pin key records with `noeviction` or a dedicated instance. ## Step 5: Revoke and Rotate Note: some of this is more advanced, so you can skip or breeze through this section. Your users will need to revoke their keys at some point, or you'll want to do it on their behalf. Revocation has one detail the other steps don't: the caller has the key's `id` (from your dashboard or admin API), not the raw key or its hash. The raw key was shown once at creation and never stored. So the flow is: 1. Look up the record by `id` to retrieve the stored `hash`. 2. Delete `apikey:{hash}` from your store so verify calls fail immediately. And don't forget removing from Redis or your cache. 3. Mark the record as revoked for your audit trail. ```javascript async function revokeKey(store, db, keyId) { // 1. Find the stored hash via the key's management ID const record = await db.findKeyById(keyId); if (!record) throw new Error('Key not found'); // 2. Remove the hot-path lookup — future verify calls return invalid_key await store.del(`apikey:${record.hash}`); // 3. Mark as revoked for auditing await db.updateKey(keyId, { enabled: false, revokedAt: Date.now(), }); } ``` If you really want to get advanced, for rotation, generate the new key _before_ revoking the old one. Store both hashes in parallel during a grace period, then delete the old hash. Stripe gives you a configurable expiration window for the outgoing key. You can build the same into your admin API so clients don't break mid-request. One caveat: a grace period is for _planned_ rotation. If a key is actually compromised, skip the overlap and revoke it immediately, because the old key keeps its full scope for as long as both hashes are live. If you add key expiry on top of rotation, a scheduled sweep that disables stale keys is all you need — a simple cron job covers it. ## Express Middleware If you're using Node.js Express, `verifyApiKey` becomes real middleware with one wrapper function: ```javascript // middleware/api-auth.js import { createHash } from 'crypto'; import { redis } from '../lib/redis.js'; const PATTERNS = { secret: /^sk_(live|test)_[0-9a-f]{32}$/, publishable: /^pk_(live|test)_[0-9a-f]{32}$/, restricted: /^rk_(live|test)_[0-9a-f]{32}$/, }; export function requireKey(type = 'secret') { const pattern = PATTERNS[type]; return async (req, res, next) => { const token = req.headers.authorization?.replace('Bearer ', ''); if (!token || !pattern.test(token)) { return res.status(401).json({ error: 'invalid_key_format' }); } const hash = createHash('sha256').update(token).digest('hex'); const raw = await redis.get(`apikey:${hash}`); if (!raw) { return res.status(401).json({ error: 'invalid_key' }); } const data = typeof raw === 'string' ? JSON.parse(raw) : raw; req.apiKey = { id: data.id, projectId: data.projectId, type }; next(); }; } ``` Wire it into your routes: ```javascript import express from 'express'; import { requireKey } from './middleware/api-auth.js'; const app = express(); app.use(express.json()); // Server-side endpoint — only sk_live_ and sk_test_ keys accepted app.post('/v1/search', requireKey('secret'), (req, res) => { console.log(`Authenticated key: ${req.apiKey.id}`); res.json({ results: ['...'] }); }); // Client-side endpoint — only pk_live_ and pk_test_ keys accepted app.post('/v1/tokenize', requireKey('publishable'), (req, res) => { res.json({ token: 'tok_...' }); }); ``` Test it with curl: ```bash curl -X POST http://localhost:3000/v1/search \ -H "Authorization: Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \ -H "Content-Type: application/json" \ -d '{"query": "test"}' ``` Or from a client app: ```javascript const res = await fetch('https://api.example.com/v1/search', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.API_SECRET_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ query: 'test' }), }); ``` Keep keys in environment variables, never in source code: ```bash # .env — add this file to .gitignore BEFORE your first commit API_SECRET_KEY=sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 ``` ## 6 Mistakes That Get API Keys Leaked **Skipping the prefix.** Millions of commits flow into public repositories every day. Without a recognizable pattern, your leaked key is invisible to every scanner on the planet. Eight characters of prefix buys you automatic detection. ![GitHub secret-scanning alert triggered by a prefixed API key in a public commit](https://cms.jamdesk.com/content/images/2026/06/github-secret-scanning-alert-2.webp) **Hardcoding keys in frontend bundles.** An `sk_live_` token in a React component ships to every browser that loads your app. Use `pk_` keys client-side and keep `sk_` keys behind server-side environment variables. **Logging the raw key in error handlers.** A failed auth check that logs `token=${rawKey}` puts plaintext credentials in your log aggregator, searchable by anyone with Datadog access. Log the key's `id` field instead. **Committing `.env` files.** Your `.env` belongs in `.gitignore` before the first commit. GitGuardian found 24,008 unique secrets exposed in MCP configuration files in 2025 alone ([GitGuardian State of Secrets Sprawl 2026](https://blog.gitguardian.com/the-state-of-secrets-sprawl-2026/?ref=cms.jamdesk.com)). **No rate limit on the verify path.** The keyspace is too large to brute-force, but that is not the real attack. Leaked and stuffed keys get replayed against your auth endpoint thousands of times a minute. Throttle failed verifications per IP and per key prefix so a stolen key trips a limit instead of running free. **No revocation endpoint.** Build one on day one, even if nobody uses it yet. 99% of surveyed organizations hit at least one API security issue in the prior 12 months ([CybelAngel](https://cybelangel.com/blog/the-api-threat-report-2025/?ref=cms.jamdesk.com), 2025). When a key leaks, and statistically it will, a single `DEL` command is all that stands between the attacker and your data. And when a leak forces a mass revocation, treat it as an incident that need to be communicated to affected customers. ## What to Build Next Five functions cover the entire key lifecycle: generate, hash, store, verify, revoke. Stripe runs this architecture at massive scale, so you know it works. If you're building API documentation alongside your keys, [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) turns your OpenAPI spec into interactive docs with a built-in playground, so developers can test endpoints with their own keys. For a wider look at the options, see our roundup of [the best API documentation tools](https://www.jamdesk.com/blog/best-api-documentation-tools?ref=cms.jamdesk.com). In summary, start with `pk_test_` and `sk_test_`. Ship the generate and verify endpoints, then add rotation when you need it. --- ## How to Create Mermaid Diagrams URL: https://www.jamdesk.com/blog/creating-mermaid-diagrams Published: 2026-06-29 *Write diagrams as plain text, commit them next to your code, and render them in GitHub, GitLab, Notion, or Jamdesk. A practical Mermaid guide with copyable examples.* When you need to add diagrams to your website, docs, or PDFs, there are a lot of options. In today's agentic world, numero uno is use an AI agent like Claude or Codex, and those usually work ok. However, the more complex the diagram, the more messed up the lines and arrows become. For example, I asked Claude with Opus 4.8 to create the same flowchart using mermaid and by hand (or by AI). Here is how it looks: ![Mermaid vs AI generated diagram](https://cms.jamdesk.com/content/images/2026/06/diagramcomparison.webp) Mermaid vs AI generated diagram On the left is a Mermaid diagram and on the right is the AI generated diagram. You can see how messy it is with text going outside the boxes, no arrows, etc. This is why diagrams-as-code is so powerful, even in an agentic world. So what is Mermaid? Essentially, Mermaid markdown inspired syntax that lets you write diagrams as plain text, commit them next to your code, and have a renderer draw them. You can change a line, open a pull request, and the diagram updates in the same review as the code it describes. This is why it is considered diagrams-as-code. The alternative is the architecture PNG or SVG (which is code, so better) that you need to maintain separately and regenerate on any changes. In the following sections, we'll cover the key areas of: * The syntax rules that unlock every diagram type. * Diagrams you can copy, paste, and adapt today. * How to wire diagrams into your Git and docs workflow. * The gotchas that trip people up, and where to write and preview. ## Why Diagrams as Code Beats Drag-and-Drop Mermaid is one of the best choices for markdown-like diagrams (others such as D2 also are popular), and the usage numbers prove it: about 9.8 million weekly downloads on npm and 88.9k stars on GitHub as of June 2026 ([npm](https://www.npmjs.com/package/mermaid?ref=cms.jamdesk.com), 2026; [GitHub](https://github.com/mermaid-js/mermaid?ref=cms.jamdesk.com), 2026). ![Mermaid weekly downloads on npm](https://cms.jamdesk.com/content/images/2026/06/image.png) npmjs.com It's open source under the MIT license and free to use anywhere. Knut Sveidqvist created it, then built a company around it ([TechCrunch](https://techcrunch.com/2024/03/20/mermaid-chart-a-markdown-like-tool-for-creating-diagrams-raises-5-5m/?ref=cms.jamdesk.com), 2024). The appeal of Mermaid is the workflow. A drag-and-drop diagram is a binary file that drifts out of sync the moment the system changes, because updating it is a separate chore from your actual work. A Mermaid diagram is lines of text in the same repo as the thing it documents. It behaves like code because it is code. The second awesome feature is portability. GitHub has drawn Mermaid blocks inside Markdown since February 2022, and GitLab, Notion, and Obsidian do too ([GitHub Blog](https://github.blog/developer-skills/github/include-diagrams-markdown-files-mermaid/?ref=cms.jamdesk.com), 2022). You can paste the same snippet into a README, a wiki, or your [docs tool](https://www.jamdesk.com/?ref=cms.jamdesk.com) and it renders with no plugin. ## The Three Rules of Mermaid Syntax Mermaid looks confusing until you notice that every diagram follows the same three rules, but if you're familiar with coding it's just a new syntax. 1. **Wrap it in a fenced code block tagged `mermaid`.** That's the signal renderers look for. 2. **Declare the diagram type on the first line**: `flowchart`, `sequenceDiagram`, `erDiagram`, and so on. 3. **Describe the nodes and the connections between them.** Mermaid handles the layout, you just need to give the flow. A simple example is a flowchart that reads top to bottom: ```mermaid flowchart TD A[Start] --> B[Do the work] --> C[Ship it] ``` `TD` means top-down (`LR` is left-to-right), square brackets make a box, and `-->` draws an arrow. Everything below builds on those primitives. ## Mermaid Diagram Examples Mermaid handles a lot more than flowcharts. Below are seven of the most common types, each with the exact syntax and the rendered result. We generated every image here from the code block beside it, so copy any one into a Markdown file on GitHub and you'll see the same thing. ### Flowcharts Flowcharts are the workhorse: any process with steps and branches. Use a curly-brace node (`{ }`) for a decision and label the branches with `|Yes|` style text. You'll see two keywords for this, `flowchart` and the older `graph`. They render almost identically, but reach for `flowchart`, since that's where new features land. ```mermaid flowchart LR A[Open PR] --> B{CI passing?} B -->|Yes| C[Request review] B -->|No| D[Fix and push] D --> B C --> E([Merge to main]) ``` ![A Mermaid flowchart showing a pull request flow with a CI-passing decision branch](https://cms.jamdesk.com/content/images/2026/06/mermaid-1-3.webp) ### Sequence Diagrams When you need to show who talks to whom and in what order, use a sequence diagram. For example, API requests, auth handshakes, or webhook retries. Solid arrows (`->>`) are calls; dashed arrows (`-->>`) are responses. ```mermaid sequenceDiagram actor User participant API participant DB as Database User->>API: POST /login API->>DB: Find user by email DB-->>API: User record API-->>User: 200 + session token ``` ![A Mermaid sequence diagram of a login request between a user, an API, and a database](https://cms.jamdesk.com/content/images/2026/06/mermaid-2-3.webp) ### Entity Relationship Diagrams ER diagrams document a database schema and the relationships between tables. The crow's-foot notation (`||--o{`) reads as "one customer places zero or many orders." ```mermaid erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE_ITEM : contains PRODUCT ||--o{ LINE_ITEM : "ordered in" CUSTOMER { int id string name string email } ORDER { int id date created_at } LINE_ITEM { int quantity decimal price } PRODUCT { int id string sku } ``` ![A Mermaid entity relationship diagram with customer, order, line item, and product tables](https://cms.jamdesk.com/content/images/2026/06/mermaid-3.webp) ### State Diagrams A state diagram models a lifecycle: the states a thing can be in, and the events that move it between them. For example, a publishing workflow, an order status, or any finite-state machine. `[*]` marks the start and the end. ```mermaid stateDiagram-v2 [*] --> Draft Draft --> InReview: submit InReview --> Draft: request changes InReview --> Published: approve Published --> [*] ``` ![A Mermaid state diagram showing a document moving from draft to in review to published](https://cms.jamdesk.com/content/images/2026/06/mermaid-4-3.webp) ### Git Graphs A git graph draws branches and merges. It's a clear way to explain a branching strategy to a new contributor without screen-sharing your terminal. It also looks like a subway map. ```mermaid gitGraph commit id: "init" branch feature checkout feature commit id: "feat-a" commit id: "feat-b" checkout main merge feature commit id: "release" ``` ![A Mermaid git graph showing a feature branch merging back into main](https://cms.jamdesk.com/content/images/2026/06/mermaid-5-3.webp) ### Gantt Charts If you need to sketch a timeline without opening a project tool, use a Gantt chart to handle schedules, with sections, durations, and dependencies with the `after` keyword. ```mermaid gantt title Docs Launch dateFormat YYYY-MM-DD axisFormat %m-%d section Writing Draft guides :a1, 2026-06-01, 7d Review :after a1, 3d section Launch Publish :2026-06-12, 1d ``` ![A Mermaid Gantt chart for a documentation launch schedule](https://cms.jamdesk.com/content/images/2026/06/mermaid-6-3.webp) ### Pie Charts For proportions, use a pie chart. It is useful for lightweight status reports, incident summaries, and "where the time went" retros. ```mermaid pie showData title Where the diagram hour goes "Editing text" : 70 "Finding the original file" : 25 "Re-exporting the PNG" : 5 ``` ![A Mermaid pie chart titled "Where the diagram hour goes"](https://cms.jamdesk.com/content/images/2026/06/mermaid-7-3.webp) ## The Workflow: Diagrams That Live in Your Pull Requests The reason to bother with any of this is the PR workflow. Because a Mermaid diagram is text, it goes through the same process your code does. Say we add a caching layer. In the same PR, we edit `architecture.md`, add a node to the flowchart, and push. The reviewer sees the diagram change rendered right in the GitHub diff, next to the code that caused it. The team member can comment on it or update. If the PR gets reverted, the diagram reverts with it, keeping everything in sync. ## Mermaid Tips and Tricks The first tip if you run into rendering issues is to check which Mermaid version a platform runs. Just add an `info` block into a Markdown file and let it render: ```mermaid info ``` GitHub will print the Mermaid version it's running, which saves you guessing why a newer diagram type won't draw ([GitHub Docs](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams?ref=cms.jamdesk.com), 2026). Next, Mermaid is forgiving until it isn't. Special characters are the big one. If a label contains syntax-like characters, wrap the text in quotes: `A["GET /users (v2)"]`. Big diagrams can also cause issues. Past 15 or so nodes the auto-layout might not render properly and the diagram looks like a mess. We recommend splitting one diagram into several, which is why our [docs guidance](https://jamdesk.com/docs/components/mermaid?ref=cms.jamdesk.com) caps each diagram at 10 to 15 nodes. Indentation also matters in some diagram types (i.e. `mindmap`), so when the syntax looks right but nothing draws, review the whitespace. ## Where to Write and Preview Mermaid The render-on-save loop is what makes Mermaid pleasant, so write somewhere you can watch the diagram appear as you type. A few good options: * **A live editor.** We built the [Jamdesk Mermaid editor](https://www.jamdesk.com/utilities/mermaid-editor?ref=cms.jamdesk.com) because the previews we'd been using blanked the whole diagram the second we typed a syntax error. Ours keeps the last valid render on screen while you fix the typo and shows the parser error inline. It's free and open-source (Apache 2.0), runs entirely in your browser, and can export the Mermaid diagram as an SVG. * **VS Code.** A [Mermaid preview extension](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart&ref=cms.jamdesk.com) renders diagrams beside your Markdown, so you never leave the editor. * **GitHub itself.** For a small tweak, edit the Markdown file in GitHub's web editor and watch the Preview tab. * **NPM package.** The [NPM Mermaid package](https://www.npmjs.com/package/mermaid?ref=cms.jamdesk.com) allows you render the diagram in JavaScript (from a web browser). If you publish documentation, check whether your [platform renders Mermaid natively](https://jamdesk.com/docs/components/mermaid?ref=cms.jamdesk.com) so you can drop a `mermaid` code block into any page and it renders, with the diagram adapting to light and dark mode automatically. When a platform has no native support, the Mermaid CLI renders any diagram to a PNG or SVG you can embed as a normal image. ## Summary Mermaid diagrams are great because they live in the repo, change in the same pull request as the code, and render the same on GitHub as they do in our docs. However, it isn't the right tool for everything. If you need pixel-perfect marketing graphics or freeform whiteboarding, try Figma. Basically, Mermaid's auto-layout trades fine control for speed/ease and are great for the technical diagrams that sit in your documentation and go stale the fastest. If you want another diagrams-as-code language, [D2](https://jamdesk.com/docs/components/d2?ref=cms.jamdesk.com) is worth a look. D2 has a clean graph syntax for some layouts, while Mermaid has broader native support across Markdown tools. --- ## 5 Best API Documentation Tools for Developers (2026) URL: https://www.jamdesk.com/blog/best-api-documentation-tools Published: 2026-06-25 *We migrated a real project between three of these tools and ran the rest against our OpenAPI spec. Honest takes on the five API documentation tools worth considering in 2026.* Fair warning before you read on: we make Jamdesk, so it sits at number one and the rest are numbered for convenience, not ranked by merit. If you just want the short answer, it comes down to how your team writes. Jamdesk and Mintlify both give you a Git-based MDX workflow — we include AI chat on every plan, Mintlify meters it by credits. When non-developers edit the docs, reach for GitBook. Docusaurus trades maintenance hours for total control; Postman only earns its place if your team already lives in it. Prices below were re-checked in June 2026; the long version, with the trade-offs, is underneath. We've been building Jamdesk, [documentation software](https://www.jamdesk.com/?ref=cms.jamdesk.com) for developers, and that means we've spent a lot of time evaluating, using, or competing against every tool on this list. Also at our previous company building social media APIs, the API docs were a core product and our best lead gen...so yeah, we have some opinions. So let's be upfront: this isn't a neutral ranking. We put Jamdesk first because we built it, and the numbering is for convenience, not a leaderboard. The other four are genuinely good tools, and for plenty of teams one of them is the better fit. We say so under each. The best software documentation tools fit your actual workflow, whether that's writing Markdown, syncing an OpenAPI spec, or generating a first draft with an AI agent. (If you're not using an LLM to help write your docs, you should be — emphasis on _help_, not handing the whole thing over.) We've spent the past few years testing, switching between, and arguing about the docs platforms on this list. We ran a real project through GitBook, then Mintlify, before building Jamdesk, and tested the rest against our own OpenAPI spec. Here is a quick outline of what we'll review: * [What Makes the Best API Documentation Tool?](#what-makes-the-best-api-documentation-tool) * [Quick Comparison Table](#quick-comparison-table) * [AI Chat for Documentation Visitors](#ai-chat-for-documentation-visitors) * [Jamdesk (Our Pick, Cause That's Us)](#1-jamdesk) * [Docusaurus](#2-docusaurus) * [Mintlify](#3-mintlify) * [GitBook](#4-gitbook) * [Postman](#5-postman) * [Honorable Mentions](#honorable-mentions) * [FAQ](#frequently-asked-questions) * [Conclusion](#conclusion) _Last updated: June 25, 2026. Pricing and features re-verified._ ## What Makes the Best API Documentation Tool? These are our thoughts on what we look for in a great software documentation tool. 1. **Great-looking, well-organized docs:** You're probably thinking that LLMs are now the consumers of the content (more on that later), and while it's trending that way, we're not there yet. Today your primary consumers are still good ol' fashioned flesh & blood developers, product managers, or CTOs. This means your docs need to be easy to read, well organized, and nice looking. 2. **Writer experience:** If your docs tool requires a WYSIWYG editor and you're a Markdown person (or someone on your team is), you're going to hate your life. The tool should match how your team writes. Bonus points for MDX, which is Markdown + JSX (React components). Maintenance overhead matters just as much. Software documentation rots fast, and if updating docs means a separate deploy pipeline from your code, they _will_ drift. The best tools sync with your Git repo so docs stay accurate alongside your codebase. 3. **OpenAPI support matters:** [OpenAPI](https://www.openapis.org/?ref=cms.jamdesk.com) allows you to automatically turn your specs into interactive docs, which saves you time and maintenance cost. Look for native ingestion of `swagger.json` or OpenAPI 3.x YAML with automatic `$ref` resolution. The difference between "import" and "sync" matters too. One-time imports go stale just like hand-written docs. 4. **AI-readiness:** In 2026 this has become a hard requirement. As mentioned above, developers aren't the only ones reading your docs, LLMs and AI agents are too. If your docs aren't structured for machine consumption ([`llms.txt`](https://jamdesk.com/docs/ai/overview?ref=cms.jamdesk.com), MCP servers, raw markdown endpoints), you're invisible to a growing chunk of your potential users. This isn't theoretical: last month, thousands of requests to our own docs came from AI crawlers — GPTBot, ClaudeBot, and PerplexityBot were the top three. We even built a 100-point rubric and [scored seven docs platforms on exactly this](https://www.jamdesk.com/blog/ai-friendly-docs-platforms-scored?ref=cms.jamdesk.com). On pure AI-friendliness, Mintlify edged us out, 87 to 85. 5. **Built-in AI chat:** Related to AI-readiness but distinct: can visitors _ask questions_ and get answers from your docs without leaving the page? A chat assistant that retrieves relevant sections and responds with citations helps visitors find answers without filing a support ticket - so it also saves your support team from having to answer basic questions. Some tools include this, some charge extra for it, and some don't offer it at all. We've also included verified pricing for every tool because most comparison articles don't, and pricing pages have a habit of changing quarterly. ## Quick Comparison Table Side-by-side of the five tools we evaluated. Pricing verified June 2026. | Tool | Best For | OpenAPI | AI-Ready | Price | | --- | --- | --- | --- | --- | | **[Jamdesk](#1-jamdesk)** | AI-first dev workflows | Native | Yes (`llms.txt`, MCP, .md) | Free trial, $29/mo | | **[Docusaurus](#2-docusaurus)** | React stacks, full control | Via plugin | No | Free | | **[Mintlify](#3-mintlify)** | Beautiful docs, fast setup | Native | Yes (`llms.txt`, MCP, .md) | Free base, AI on credits | | **[GitBook](#4-gitbook)** | Non-technical contributors | Native | Yes (`llms.txt`, MCP, .md) | Free, $65/site/mo | | **[Postman](#5-postman)** | Teams already testing there | Import only | No | Free (1 user), $19/user/mo | ### AI Chat for Documentation Visitors Not all tools include a built-in chat assistant that answers questions from your docs. How they compare: | Tool | AI Chat | Chat Cost | | --- | --- | --- | | **Jamdesk** | Built-in (RAG + citations) | Included, all plans | | **Docusaurus** | None (third-party required) | Varies | | **Mintlify** | On Starter (credit-metered) | Credits from $100/mo | | **GitBook** | AI search, Premium+ | $65/site/mo + overage | | **ReadMe** | Add-on (Ask AI) | $150/mo add-on | | **Postman** | None on published docs | N/A | _ReadMe isn't one of our five picks (it's in Honorable Mentions below), but we list it here for chat-cost comparison._ _AI-Ready = machine-readable outputs (`llms.txt`, MCP server, structured markdown endpoints) so LLMs and AI agents can consume your docs. This is separate from reader-facing AI chat. See the_ [_AI chat comparison_](#ai-chat-for-documentation-visitors)_._ * * * ## 1\. Jamdesk ![Jamdesk API documentation interface showing interactive OpenAPI endpoints with request and response examples](https://cms.jamdesk.com/content/images/2026/02/jamdesk-api-docs.webp) Jamdesk documentation _We built Jamdesk because we kept hitting the same walls with existing tools._ [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) is a [software documentation tool](https://www.jamdesk.com/?ref=cms.jamdesk.com) built around how developers actually work: write in [MDX](https://jamdesk.com/docs/ai/markdown-source?ref=cms.jamdesk.com) (Markdown with JSX components), store it in Git, deploy on merge, and included AI Chat. Your docs live next to your code and follow the same review process. Take a quick glance at [how our docs look.](https://jamdesk.com/docs/introduction?ref=cms.jamdesk.com) You can [manually create API docs and request/response examples](https://jamdesk.com/docs/api-reference/request-response-examples?ref=cms.jamdesk.com) when you need granular control over what developers see, or point Jamdesk at your OpenAPI 3.x spec in YAML or JSON and [auto-generate interactive endpoints](https://jamdesk.com/docs/api-reference/openapi-example?ref=cms.jamdesk.com) with `$ref` resolution handled for you. Wiring up an endpoint takes one line of frontmatter: ```yaml --- title: "Create User" openapi: /openapi/spec.yaml POST /users --- ``` That gives you request parameters, response schemas, and code examples in multiple languages, all pulled from your spec. The docs-as-code workflow is the part we use daily. Write MDX in your editor, commit to Git, review in a PR, and your docs deploy on merge. If a developer changes an API endpoint and updates docs in the same PR, the reviewer sees both changes together. No drift. ### AI-Ready Docs AI-readiness is where we've spent the most engineering time. In 2026, your docs need to serve two audiences: humans and machines. Three features ship automatically. 1\. Every site gets a standardized `llms.txt` endpoint, which is a page index and full-content dump that LLMs can consume directly, no configuration needed. For example: ```bash curl https://your-docs.jamdesk.app/llms.txt ``` 2\. A built-in MCP server lets AI agents query your docs programmatically via the [Model Context Protocol](https://jamdesk.com/docs/ai/overview?ref=cms.jamdesk.com). 3\. Two tools out of the box: `searchDocs` and `getPage`, so agents don't have to scrape HTML. And you can append `.md` to any docs page URL to get clean markdown. No parsing, no scraping, no HTML mangling. Beyond machine consumption, **every Jamdesk site also ships with a built-in AI chat assistant at no additional cost**. Visitors click "Ask AI," type a question, and get a streamed response grounded in your documentation with citation links back to the source pages. Under the hood it's a RAG pipeline: your pages are chunked and indexed as vector embeddings during each build, and queries run hybrid keyword + semantic search before hitting Claude for an answer. It's included on all plans at no extra cost. There's also a dashboard for builds and deployments, a [CLI](https://jamdesk.com/docs/cli/overview?ref=cms.jamdesk.com) that previews docs locally and flags broken links and bad OpenAPI refs before you ship, and [customizable themes](https://jamdesk.com/docs/customization/theming?ref=cms.jamdesk.com). End Notes: * [jamdesk.com](https://www.jamdesk.com/?ref=cms.jamdesk.com) | [quickstart guide](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com) * **Pricing:** [14-day free trial](https://www.jamdesk.com/pricing?ref=cms.jamdesk.com) with full access, card required, $0 today. Pro is $29/month. Enterprise is custom. * OpenAPI 3.x (YAML or JSON) supported natively, out of the box. Jamdesk is newer, which means fewer secondary features: no i18n, docs versioning, or WYSIWYG editor yet. No free tier beyond the 14-day trial either; if you need permanently free hosting, look at Docusaurus or GitBook's Basic plan. * * * ## 2\. Docusaurus ![Docusaurus API documentation site with sidebar navigation and MDX content layout](https://cms.jamdesk.com/content/images/2026/02/docusaurus-docs.webp) Docusaurus documentation [Docusaurus](https://docusaurus.io/?ref=cms.jamdesk.com) is Meta's open-source static site generator, built on React, and is self-hosted. It renders MDX to plain HTML with no server needed. Meta uses it for their own docs, and so do React, Jest, Babel, and dozens of other major open-source projects. If you're evaluating documentation tools, you'll probably compare everything to Docusaurus at some point, because it's free, it's been around for a while, and it does mostly everything. Mostly because Docusaurus is self-hosted, so you're maintaining a React application just to have documentation and all the headaches that come with it. For example, when `docusaurus.config.ts` breaks after a major version bump, that's your Friday night. The hands-on maintenance is what wore us down: we spent more time on Docusaurus builds and configs than on writing actual documentation, and it's the kind of tool that works beautifully for the first six months and then quietly becomes someone's part-time job. That said, a lot of that config-wrangling is now the sort of thing an AI coding assistant handles for you, so the maintenance tax may be lighter today than it was for us. Your mileage may vary. The ecosystem makes up for a lot of that pain, though. Algolia DocSearch for search, deep theme customization, built-in versioning and i18n. Most hosted tools charge extra for these. If you need something specific (custom sidebar, code playground, API explorer), you can build it in React and drop it in. No other tool on this list gives you that level of control. OpenAPI support comes via the community plugin [`docusaurus-plugin-openapi-docs`](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs?ref=cms.jamdesk.com). It works, but it requires manual setup in your config and doesn't auto-sync on spec changes without additional CI work. Updating your spec means rebuilding and redeploying. There are also no AI-readiness features: no `llms.txt`, no MCP server, no structured markdown endpoints. You'd have to build all of that yourself or use [a community plugin](https://github.com/din0s/docusaurus-plugin-llms-txt?ref=cms.jamdesk.com). And the default theme screams "generic React app" unless you invest real CSS time. No built-in AI chat either. If you want visitors to ask questions from your docs, you're looking at Algolia's paid Ask AI (bring your own LLM key), or a third-party widget like Biel.ai or DocuScout. End Notes: * [docusaurus.io](https://docusaurus.io/?ref=cms.jamdesk.com) | [getting started](https://docusaurus.io/docs/installation?ref=cms.jamdesk.com) * **Pricing:** Free * Free and endlessly flexible, but you maintain the React app yourself and bolt on community plugins for OpenAPI and AI-readiness. * * * ## 3\. Mintlify ![Mintlify API documentation with dark mode theme and clean typography](https://cms.jamdesk.com/content/images/2026/02/mintlify-docs.webp) Mintlify documentation [Mintlify](https://mintlify.com/?ref=cms.jamdesk.com) has earned its reputation for one reason: it makes docs look good without a designer. Dark mode, clean typography, responsive layout, all out of the box and no CSS required. You write MDX, push to your Git repo, and Mintlify deploys it. They've also built AI features for documentation drafting and `llms.txt` generation, plus analytics that show where developers get stuck, which is genuinely useful for iterating on content. The big news in 2026 is that the free tier (now called Starter) got genuinely good: custom domains, API playground, custom components, the works. A solo developer or a small open-source project can run a production-quality docs site on Mintlify without paying a cent. That changes the math if you're comparing hosted tools. Where it gets complicated is the AI. Mintlify dropped the old $300/month team tier, which sounds like a win until you read the credits page. The AI features (the assistant, the writing agent) now run on credits: 5,000 free your first month, then nothing recurring, so real usage means buying bundles that start at $100/month for 10,250 credits and climb to $1,000. Overage is a cent a credit. The flat price went away; the AI bill didn't. OpenAPI support is native, with an interactive playground auto-generated from your spec. Customization beyond their component library means learning Mintlify's particular MDX flavor, which doesn't always behave like standard MDX. One more thing: Mintlify's AI chat assistant, the one that answers visitor questions from your docs, draws on that same credit pool. It's on Starter now, which is an improvement, but a busy docs site burns through credits fast, so budget for it. End Notes: * [mintlify.com](https://mintlify.com/?ref=cms.jamdesk.com) | [quickstart guide](https://mintlify.com/docs/quickstart?ref=cms.jamdesk.com) * **Pricing:** Free Starter tier (fully functional). [AI runs on credits](https://mintlify.com/pricing?ref=cms.jamdesk.com): 5,000 free the first month, then bundles from $100/month, or $0.01 per credit. Enterprise is custom. * OpenAPI is native with an auto-generated interactive playground. * * * ## 4\. GitBook ![GitBook API documentation workspace with block-based editor and published page](https://cms.jamdesk.com/content/images/2026/02/gitbook-docs.webp) Gitbook documentation [GitBook](https://www.gitbook.com/?ref=cms.jamdesk.com) is the tool you reach for when your PM keeps asking for edit access and you don't want to teach them Markdown, even though we think Markdown is pretty easy. It started as a book-writing tool and evolved into a knowledge base with a block-based WYSIWYG editor (drag-and-drop blocks, slash commands, the Notion pattern). Bi-directional Git sync with GitHub/GitLab means developers can keep working in their editor while non-technical contributors use the web UI. Inline comments, change requests, and a clean collaboration interface make it feel more like Google Docs than a developer tool. That accessibility is what makes GitBook good, and also what limits it. The published output looks more like an internal wiki than a polished API reference. If you're trying to match the feel of Stripe's or Twilio's docs, GitBook won't get you there without significant customization effort. It works well for teams where multiple roles contribute, but it prioritizes approachability over technical depth. OpenAPI support is native with interactive docs generated from your spec, and AI-readiness is solid too. GitBook auto-generates `llms.txt` and `llms-full.txt`, supports `.md` URLs for any page, and hosts an MCP server for published docs. Pricing is where GitBook gets tricky. The free Basic tier is limited to a single user, which works for personal projects but not teams. On the monthly plan, Premium is $65/site/month + $12 per additional user. Note the _per-site_ part: if you need separate docs for multiple products, you're paying that base fee for each one. Costs add up fast, and their pricing page makes it harder to figure out than it should be. GitBook's AI-powered search is available starting at the Premium tier. It works within a single space, but cross-site AI search requires the Ultimate plan at $249/site/month. The per-site pricing model means costs scale with each documentation project you maintain. End Notes: * [gitbook.com](https://www.gitbook.com/?ref=cms.jamdesk.com) | [quickstart guide](https://gitbook.com/docs/quickstart?ref=cms.jamdesk.com) * **Pricing:** Free tier, no custom domain or AI. Paid plans start at Premium: [GitBook pricing](https://www.gitbook.com/pricing?ref=cms.jamdesk.com) at $65/site/month plus $12 per user; Ultimate is $249/site/month on the monthly plan. * OpenAPI is native with interactive docs from your spec. At our previous company we ran on GitBook for years, then moved to Mintlify when we needed more flexibility — we weren't fans of how GitBook displayed API docs. Jamdesk came later. * * * ## 5\. Postman ![Postman API documentation showing endpoint details and collection overview](https://cms.jamdesk.com/content/images/2026/02/postman-docs.webp) Postman documentation [Postman](https://www.postman.com/?ref=cms.jamdesk.com) isn't primarily a documentation tool. It's an API client and testing platform that happens to generate docs as a side feature. If your team already lives in Postman for building and testing endpoints, generating documentation from your collections is the path of least resistance. You document your collections, add descriptions and examples, and Postman publishes them to a web-friendly portal. The "Run in Postman" button is the real differentiator. Developers viewing your docs can fork the collection and test endpoints locally with one click, and no dedicated docs tool replicates that workflow well. Mock servers and automated testing integrations are built in too. But that's about where the good news ends for documentation purposes. The published docs are functional but bland, with limited customization and limited branding. If you need conceptual guides, architecture overviews, or tutorials alongside the reference, you'll need a second tool. OpenAPI is import-only (no live sync, so spec changes require re-importing), and there are no AI-readiness features at all. The free tier also tightened. It's a single user now, down from three, so any real team lands on a paid plan. Paid starts at $19/user/month on the Team plan (there's a $9 Solo tier, but it's single-seat). Not the bargain it used to be. AI features exist (Postbot, agent mode), but they're for developers inside the Postman app — building tests, generating collections. No AI-powered chat or Q&A on the published documentation portal. End Notes: * [postman.com](https://www.postman.com/?ref=cms.jamdesk.com) | [quickstart guide](https://learning.postman.com/docs/getting-started/overview?ref=cms.jamdesk.com) * **Pricing:** [Free for a single user](https://www.postman.com/pricing?ref=cms.jamdesk.com), then $19/user/month on the Team plan (annual). OpenAPI is import-only with no live sync. * * * ## Honorable Mentions Five tools isn't exhaustive. A few others show up in every roundup for good reason: * [**Redocly**](https://redocly.com/?ref=cms.jamdesk.com) — Open-core API docs platform. The free [Redoc](https://github.com/Redocly/redoc?ref=cms.jamdesk.com) renderer generates a clean three-panel API reference as static HTML. Commercial platform adds Try-it consoles and API governance, starting at $10/user/month. Their open-source [CLI](https://github.com/Redocly/redocly-cli?ref=cms.jamdesk.com) for linting OpenAPI specs is worth using even if you host docs elsewhere. * [**ReadMe**](https://readme.com/?ref=cms.jamdesk.com) — Full developer portal with analytics, "Try It" playground, and user-specific API keys in code examples. Pro starts at $250/month, with the "Ask AI" add-on a further $150/month. * [**Fern**](https://buildwithfern.com/?ref=cms.jamdesk.com) — Generates client SDKs in 9+ languages, docs, and a CLI from a single API definition (now part of Postman). Strong if you need SDKs, but AI chat is metered by credits and the Team plan caps at five seats. For docs without the SDK toolchain, see [how Jamdesk compares as a Fern Docs alternative](https://www.jamdesk.com/compare/fern-docs-alternative?ref=cms.jamdesk.com). * * * ## Frequently Asked Questions ### What is the best software documentation tool? Depends on your team and workflow. For AI-first documentation with OpenAPI support and a Git-based workflow, [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) is our recommendation because we're biased! After Jamdesk, we would lean towards Mintlify if it fits your budget. For teams that want full control and don't mind maintaining a React project, Docusaurus is hard to beat on flexibility. See the [comparison table](#quick-comparison-table) for a side-by-side breakdown. ### Is Postman good for API documentation? For endpoint reference, yes — especially if your team already uses Postman for testing. The "Run in Postman" button is great for adoption. For guides, tutorials, or conceptual docs, you'll need a second tool. ### Do I need a dedicated API documentation tool? If you have 3 endpoints and 10 users, a README is fine. Once you have versioned endpoints, multiple audiences, or an OpenAPI spec you want to keep in sync, a dedicated software documentation tool pays for itself by keeping docs accurate as your API grows. ### What's the cheapest API documentation tool? Free, if you self-host: Docusaurus costs nothing but your time. Among hosted tools, Mintlify's Starter and GitBook's free tier both run $0 for small projects. For paid team plans, Redocly starts at $10/seat/month, undercutting Postman's $19/user. "Cheapest" usually means trading money for maintenance hours or AI credits, though. ### Which API documentation tools support OpenAPI? Jamdesk, Mintlify, and GitBook ingest an OpenAPI 3.x spec natively and generate interactive endpoints. Docusaurus needs a community plugin. Postman is import-only: it reads your spec once but won't stay in sync as it changes. If live sync matters to you, that's the distinction to watch. * * * Choosing **API documentation software** often comes down to a head-to-head call between two platforms. For deeper breakdowns, see [Mintlify vs ReadMe](https://www.jamdesk.com/compare/mintlify-vs-readme?ref=cms.jamdesk.com) and [GitBook vs Mintlify vs ReadMe](https://www.jamdesk.com/compare/gitbook-vs-mintlify-vs-readme?ref=cms.jamdesk.com). ## When You Are Ready Most teams should start with Docusaurus or Mintlify's free tier and see how far they get. Docusaurus gives you everything, but you'll feel it in maintenance hours. Someone on your team will end up babysitting the build pipeline. Mintlify looks better out of the box than anything else on this list, and the free Starter tier is useful now. The sting moved from the old $300 tier to the AI credits — fine if your docs are quiet, a real line item once traffic picks up and people lean on the assistant. GitBook is the right call when your docs team includes non-developers who refuse to touch a text editor. And Postman docs are a checkbox feature, not a documentation strategy — use them if you're already there, but don't build your software documentation around them. We built Jamdesk for teams that want AI-readiness, built-in AI chat for docs visitors, and a Git workflow without maintaining their own static site generator - and affordability is important. If that sounds like your situation, [try it free for 14 days](https://www.jamdesk.com/?ref=cms.jamdesk.com) and see if the workflow clicks. If not, the other four tools are all solid. The right one is whichever matches how your team actually writes and ships. Did we miss a tool you swear by? We update this list regularly, so [let us know](mailto:contact@jamdesk.com). _Last updated: June 25, 2026_ --- ## How to Resolve Promises Sequentially in JavaScript URL: https://www.jamdesk.com/blog/resolve-promises-sequentially-javascript Published: 2026-06-24 *In JavaScript, the Promise.all() function is one of your best tools when you want to do async work. You can fire everything off, wait for the slowest one to complete, and then continue processing. However, sometimes running it all at once is exactly what breaks production. When you need promises to run in order, one finishing before the next begins, the answer is a for...of loop with await inside it. Easy right? Well, the catch is a subtlety that bites almost everyone the first time; if you've * In JavaScript, the [Promise.all() function](https://www.jamdesk.com/blog/javascript-promise-all?ref=cms.jamdesk.com) is one of your best tools when you want to do async work. You can fire everything off, wait for the slowest one to complete, and then continue processing. However, sometimes running it all at once is exactly what breaks production. When you need promises to run in order, one finishing before the next begins, the answer is a `for...of` loop with `await` inside it. Easy right? Well, the catch is a subtlety that bites almost everyone the first time; if you've already created your promises, they've already started (whoops). Awaiting them in order doesn't make the _work_ sequential. It just makes you wait while it all runs at once anyway. ## Why Would You Run Promises Sequentially? Because all-at-once isn't free. Every concurrent promise is a concurrent connection, a concurrent write, another request landing on something that may have a rate limit. On the social API I worked on at my previous company, we social analytics jobs that gathers data for hundreds of posts, with multiple API calls per post. The first version mapped them straight into `Promise.all()`. In production it slammed thousands of simultaneous requests to the social media networks, tripped the rate limit, and the whole job fell over. \*the social networks' APIs have severe limit and basically you need to make sequential calls. The solution wasn't more retries, but rather to stop asking for everything at once. Sequential resolution allowed us to stay within the social network APIs rate limits, and the job started finishing instead of failing. Same story shows up whenever order matters: database migrations that have to run in sequence, writes where step two depends on step one landing first, or any API that starts returning `429` the second you get enthusiastic. ## Why forEach and map Won't Wait This is the crux of the problem that sends most people searching for an answer in the first place: you use `forEach`, add an `await` inside each callback fully expecting it to pause between items, and instead the loop sprints right past every one of them without waiting. Unfortunately, this doesn't work, and yes, JavaScript can sometime suck. ```javascript // Looks sequential. Isn't. [id1, id2, id3].forEach(async (id) => { const user = await getUser(id); console.log(user.name); }); console.log("Done!"); // Prints FIRST, before any user ``` `forEach` doesn't understand promises. The callback returns one, `forEach` shrugs and throws it away, and all three lookups launch on the same tick. "Done!" logs before a single user comes back, and you haven't sequenced anything. You've just made the chaos harder to see. The same applies to `.map()` if you're after ordering. `.map()` is great for _building_ an array of promises to hand to `Promise.all()`, but the mapping itself kicks every promise off immediately. Map for concurrency. Loop for sequence. ## The Sequential Pattern: for...of With await This is the version that actually works. A plain `for...of` loop pauses at each `await`, so the next iteration doesn't start until the current promise resolves. ```javascript const resolveSequentially = async (tasks) => { const results = []; for (const task of tasks) { results.push(await task()); } return results; }; ``` Notice `task()`, not `task`. That parenthesis is the entire point. We pass an array of **functions**, and call each one _inside_ the loop, so the promise isn't created until its turn comes up. Defer the creation and you defer the work. Compare the two ways to feed it: ```javascript // Wrong: every getUser() fires during .map(), all at once. Awaiting them // in a loop afterward orders the results, not the work. const started = uids.map((uid) => getUser(uid)); const results = []; for (const p of started) results.push(await p); // Right: each getUser() fires only when the loop reaches it. const tasks = uids.map((uid) => () => getUser(uid)); await resolveSequentially(tasks); ``` The difference is all timing: the first version calls `getUser` while building the array, so every request is already in flight before the loop even runs. Only the second one actually protects Firebase, because only the second one defers each call until the loop reaches it. This is the bit most tutorials gloss over. If your goal is to ease load and not just collect results in order, you have to hand the loop work it hasn't begun yet. ## How Do You Handle Errors Mid-Loop? One rejection in a `for...of` loop throws straight out and abandons every task you hadn't reached yet. Sometimes that's what you want. Often it isn't, especially in a batch job where one bad record shouldn't sink the other 2,000. Wrap each call and decide per item: ```javascript const resolveSettled = async (tasks) => { const results = []; for (const task of tasks) { try { results.push({ status: "fulfilled", value: await task() }); } catch (error) { results.push({ status: "rejected", reason: error }); } } return results; }; ``` That's `Promise.allSettled()` behavior, one task at a time. Keep going, record what failed, sort it out at the end. If instead you want to bail on the first error, skip the `try/catch` and let it throw. The loop stops exactly where it broke, which is handy when later steps depend on earlier ones succeeding. ## What About for await...of? When the source itself is async, not just the work, `for await...of` is the cleaner tool. It's built for async iterables, specifically a paginated endpoint, a database cursor, a readable stream. Each iteration awaits the next chunk before handing it to you. ```javascript async function* fetchPages(url) { let next = url; while (next) { const res = await fetch(next); const page = await res.json(); yield page.items; next = page.nextPageUrl; } } for await (const items of fetchPages("/api/users")) { await saveBatch(items); // one page lands before the next is requested } ``` You never hold every page in memory, and you never request page two before page one is safely written. `for...of` sequences tasks you already have. `for await...of` sequences tasks that arrive over time. Reach for it when the data shows up lazily ([MDN: for await...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of?ref=cms.jamdesk.com)). ## Sequential or Concurrent: Which Do You Actually Need? Most of the time the honest answer is "neither extreme." Picking by what each one optimizes for: | Approach | How | Best for | Cost | | --- | --- | --- | --- | | All at once | `Promise.all()` | Independent calls, speed matters | Floods rate-limited services | | One at a time | `for...of` + `await` | Ordered writes, strict rate limits | Slow: the sum of every call | | N at a time | Batches or a concurrency limiter | The real world | A few more lines of code | Pure sequential is the safe default when something downstream is fragile, but it leaves a lot of speed on the table. Run a thousand tasks one at a time and you wait for all thousand end to end. The middle ground, processing a handful at a time, usually wins: fast enough to finish, gentle enough not to get throttled. A small helper or a library like [`p-limit`](https://github.com/sindresorhus/p-limit?ref=cms.jamdesk.com) caps how many promises run at once, and that's a post of its own. For now, the rule is simple. Independent and urgent, use `Promise.all()`. Ordered or rate-limited, loop with `await`. Somewhere between, cap your concurrency. ## Wrapping Up Sequential promise resolution comes down to one loop and one habit: pass functions, not already-running promises, so the work waits its turn. And don't forget to add a `try/catch` when a single failure shouldn't end the batch, and graduate to `for await...of` when the data itself arrives asynchronously. --- ## Which docs platforms are AI-friendly? We scored seven. URL: https://www.jamdesk.com/blog/ai-friendly-docs-platforms-scored Published: 2026-06-04 *We wanted a measurable number on which docs platforms are AI-friendly, and honestly to see how Jamdesk stacks up against the competition. So we wrote a small Node.js script that probes a documentation software docs site for the things AI crawlers and agents actually care about: server-rendered HTML, a content-to-chrome ratio, discovery files like llms.txt, a .md-endpoint convention, robots.txt posture, and the ratio of repeated boilerplate between pages. Then we layered a manual answer-quality r* We wanted a measurable number on which docs platforms are AI-friendly, and honestly to see how Jamdesk stacks up against the competition. So we wrote a small Node.js script that [probes a documentation software docs site](https://github.com/jamdesk/docs-ai-scorer?ref=cms.jamdesk.com) for the things AI crawlers and agents actually care about: server-rendered HTML, a content-to-chrome ratio, discovery files like `llms.txt`, a `.md`\-endpoint convention, robots.txt posture, and the ratio of repeated boilerplate between pages. Then we layered a manual answer-quality rubric on top, graded by Claude Opus 4.8 against the rendered page text. Why are these metrics important? The discovery world is changing, with people frequently using AI chat like ChatGPT or Gemini to do their searches. Your docs can't rely on organic Google search alone anymore. We ran it against seven platforms, including our own. And before the results, we owe you the story of the bug. ## We found a bug in our own scorer, and it had us winning Our first internal draft put Jamdesk tied for first. Hip, hip, hooray! Then one of us actually re-read the script. The discovery check looked for `llms.txt` at the **bare origin root**, `https://example.com/llms.txt`. That quietly rewards any platform that mirrors its `llms.txt` to the apex domain and penalizes any platform that serves it from a subpath like `/docs/llms.txt`. Jamdesk publishes `llms.txt` at the root _and_ the subpath, so we passed. Mintlify publishes a perfectly good `llms.txt` (43 KB of it, plus a 1.1 MB `llms-full.txt`) at `mintlify.com/docs/llms.txt`. Our script asked `mintlify.com/llms.txt`, got a 404, and recorded "no `llms.txt`." That one false negative cost Mintlify 10 points and dropped them from first to fourth. It's the difference between the draft we almost published and the truth. So we fixed the probe. It now checks the root _and_ every path segment down to the page it's testing, follows redirects, and verifies the file is real markdown rather than an SPA shell. We re-ran everything on 2026-06-01. The corrected result: **Mintlify won, 87 out of 100. Jamdesk tied ReadMe.com for second at 85.** We build Jamdesk, [documentation software](https://www.jamdesk.com/?ref=cms.jamdesk.com) designed around AI-readable output, and the honest version of this comparison is we don't win today. The mechanical signals come from a single open-source Node.js script at [github.com/jamdesk/docs-ai-scorer](https://github.com/jamdesk/docs-ai-scorer?ref=cms.jamdesk.com) (the fixed version). The point weighting is the mapping described in the next section, and Answer Quality is a manual grade by Claude Opus 4.8 against the rendered page text. The raw signals are below, not just the rankings. If your numbers come out different, the README has a one-click way to submit a counter-run. > The lesson for anyone building a benchmark: the first time your own tool says you're winning, that's exactly when to go re-read the code and re-check everything. ## What we measured The scoring formula has five dimensions, weighted to a 100-point total: * **Crawlability (25).** Does the page server-render its content? `ssrPass` is worth 15 points: a non-empty `

`, at least two visible headings, and more than 500 characters of stripped text. The remaining 10 come from `textRatio` (stripped text bytes ÷ total HTML bytes) on a tiered scale. * **AI Discovery (25).** `llms.txt` worth 10 (either `llms.txt` or `llms-full.txt` present, found at the root _or_ a subpath; we count them as one signal because shipping one is essentially the same architectural decision as shipping the other), a per-page `.md` companion endpoint worth 12, `sitemap.xml` worth 3. * **Robots Policy (10).** Fraction of the major AI crawlers (GPTBot, ClaudeBot, Claude-Web, PerplexityBot, Google-Extended, CCBot) not explicitly disallowed at root. * **Context Noise (15).** `(1 − page1NoiseRatio) × 15`. Noise ratio is the byte overlap between two pages on the same site, chunked at 200 bytes. High overlap means most of the page is sidebar, header, and footer rather than content. * **Answer Quality (25).** Five questions from a developer onboarding flow, graded 0-3 each: what is the product, how do I get started, do I need an account, where's the feature/command list, where do I get help. The grader (Claude Opus 4.8) saw only the rendered page text, no follow-up fetches, no web search. These five dimensions are basically a proxy for one question: can an agent fetch, parse, and trust your docs without executing the page's JavaScript? The full script is at the bottom of this article. It's about 200 lines with no dependencies, and runs on plain Node 20+. It emits the raw signals; the point values above are how we map those signals to a score, and Answer Quality is the one manual step. ## Results Listed alphabetically. Totals are in the rightmost column. Tested 2026-06-01 against each platform's own docs site. | Platform | Crawl /25 | Discovery /25 | Robots /10 | Noise /15 | Answer /25 | **Total /100** | | --- | --- | --- | --- | --- | --- | --- | | Document360 | 0 | 10 | 10 | 12 | 10 | **42** | | Docusaurus | 22 | 3 | 10 | 15 | 15 | **65** | | GitBook | 15 | 25 | 10 | 14 | 18 | **82** | | Jamdesk | 15 | 25 | 10 | 15 | 20 | **85** | | Mintlify | 15 | 25 | 10 | 15 | 22 | **87** | | ReadMe.com | 15 | 25 | 10 | 15 | 20 | **85** | | Stripe (raw MD on GitHub) † | 10 | 0 | 10 | 15 | 7 | **42** | † Stripe's `ARCHITECTURE.md` is a contributor-facing internals doc served raw from GitHub. We include it as a "raw markdown, no platform" baseline, not as a fair comparison to the user-facing onboarding pages used for the other six. Rerunning against `README.md` would lift its answer-quality score. **Top of the table: Mintlify at 87, then Jamdesk and ReadMe.com tied at 85, then GitBook at 82.** Four platforms sit within five points of each other. Mintlify wins on the best content in the test. More on that below. Raw signals (for audit) | Platform | ssrPass | textRatio | llms.txt | location | .md | sitemap | noiseRatio | answerQ /15 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Document360 | false | 0.001 | yes | subdomain root | no | no | 0.203 | 6 | | Docusaurus | true | 0.132 | no | — | no | yes | 0.003 | 9 | | GitBook | true | 0.016 | yes | subdomain root | yes | yes | 0.038 | 11 | | Jamdesk | true | 0.030 | yes | **root + subpath** | yes | yes | 0.005 | 12 | | Mintlify | true | 0.008 | yes | subpath (`/docs/`) | yes | yes | 0.015 | 13 | | ReadMe.com | true | 0.016 | yes | subdomain root | yes | yes | 0.004 | 12 | | Stripe (raw MD on GitHub) | false | 0.996 | no | — | no | no | 0.000 | 4 | The `location` column is the thing the bug was hiding. Five of the seven ship `llms.txt`. All five are real, spec-compliant files. The only difference is _where_ they live. ## Mintlify earned first place on content Mintlify scored **13 out of 15** on answer quality, the highest in the test. Its quickstart explains what the product is, how to deploy, and how to authenticate, with explicit instructions and numbered steps. The writing is good, and it's why Mintlify tops the table even though it's tied with three other platforms on every mechanical signal. It also ships everything an AI crawler wants: server-rendered HTML, a `.md` endpoint, a sitemap, and both `llms.txt` and `llms-full.txt`. Our broken draft said the opposite. ## The top four are separated by content, not infrastructure The corrected table tells a plainer story. GitBook, Jamdesk, Mintlify, and ReadMe.com all ship the full discovery picture (`llms.txt`, `llms-full.txt`, and a per-page `.md` companion endpoint) on server-rendered HTML, with every AI bot allowed. The infrastructure layer is **settled** among the leaders. What separates them is answer quality, measured in single rubric points. That makes the gaps small and a little fragile. Jamdesk and ReadMe.com tie at 85 because they match bit-for-bit on Crawlability, Discovery, Robots, and Noise, and land on the same answer-quality score (12/15). Mintlify pulls ahead by one rubric point on a single onboarding question. A one-point swing on the 15-point rubric is a 1.67-point swing on the 100-point total, small enough that a different set of grading questions could reorder the top four. > **Update, 2026-06-01:** Jamdesk shipped a clearer support pathway into the [quickstart](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com) after an earlier run flagged it as our weakest answer. We're noting that rather than re-grading inline, because re-running a rubric on a fix made by the team that owns the rubric isn't cool. The next full re-run re-grades every platform, not just ours. ## Where Jamdesk does have an edge Tied for second isn't first, and we won't dress it up. But two of Jamdesk's signals are the best in the field, and both matter to an agent. **Leanest HTML of the hosted leaders.** Among the four platforms at the top, Jamdesk's `textRatio` of 0.030 is the highest: 0.016 for GitBook and ReadMe, 0.008 for Mintlify, roughly 3.7× more content per byte than Mintlify. (Docusaurus and the raw GitHub file score higher still on this one signal, but they're a static-site generator and a single markdown file, not hosted platforms, and they pay for it elsewhere.) When an agent fetches the HTML version of a Jamdesk page, about 3% of what it downloads is content; for Mintlify it's 0.8%. The `.md` endpoint sidesteps this. Fetching `jamdesk.com/docs/quickstart.md` returns about 6 KB of clean markdown instead of roughly 200 KB of HTML. Not every agent asks for the `.md` view, though, and the ones that fall back to HTML pay the token bill. **`llms.txt` where an agent guesses it.** Jamdesk serves `llms.txt` at the root path `/llms.txt` (the location the [llms.txt spec](https://llmstxt.org/?ref=cms.jamdesk.com) names first) _and_ at the docs subpath. Mintlify serves a great file, but only at `/docs/llms.txt`; an agent that requests the bare `mintlify.com/llms.txt` gets a 404. The spec explicitly permits subpaths, so this is a discoverability nuance, not a deficiency. It's a real one, though, and it's one redirect away from being closed. Neither edge earns points the rubric currently awards: the `textRatio` tier doesn't separate 0.030 from 0.008, and we score `llms.txt` on presence, not location. We're flagging them as honest observations, not a thumb on the scale. Re-weighting the rubric _now_, after seeing the results, to turn these into a Jamdesk win would be exactly the move this whole post is the opposite of. ## About the weights We picked the weights, and we tried to be fair. Discovery at 25 and Answer Quality at 25 reflects our judgment that AI agents need both a way to find canonical content and content that actually answers things. If you disagree, you can change the weights in the script and run again. One adjustment we made up front: `llms.txt` and `llms-full.txt` count as a single 10-point signal, not two. They're highly correlated (every platform that ships one ships the other), so counting them separately would double-count one architectural decision. We ship both and like them both; we don't think we should be rewarded twice for that. The same signals under a few other schemes: | Scheme | Crawl | Disc | Robots | Noise | Answer | Top platform | | --- | --- | --- | --- | --- | --- | --- | | Current (ours) | 25 | 25 | 10 | 15 | 25 | Mintlify (87) | | Content-heavy | 20 | 15 | 5 | 10 | **50** | Mintlify (wider lead) | | Extractability-heavy | **40** | 20 | 5 | 20 | 15 | Docusaurus closes on the leaders | Mintlify wins our default and the content-heavy view; Docusaurus closes the gap if you mostly care about raw extractability. Pick the weighting that matches what you need. The script outputs the raw signals, and re-weighting just means changing the point values listed above. ## Document360 served 1.05 MB of HTML for 1.3 KB of text This is the strongest negative finding in the test, and the bug fix didn't touch it. We requested `docs.document360.com/docs/getting-started`. The response was **1,049,919 bytes of HTML**. The stripped-text content was **1,279 bytes**. That's a `textRatio` of 0.001, the worst we measured. The reason is client-side rendering. The HTML is a thin SPA shell that defers all content to JavaScript. The body of the article isn't in the response at all. An AI crawler reading this URL with plain HTTP sees navigation chrome and a loading spinner, nothing more. Document360 _does_ ship an `llms.txt` (credited with 10 points), which lifts its corrected total from the broken draft's 32 to 42. But the rendering choice still produces the lowest crawlability score in the test (0/25) and the highest noise ratio (20.3% repeated boilerplate). For a hosted platform customers pay for, the rendering pipeline is something the vendor controls and the customer can't fix. That's the part worth watching. ## Raw markdown on GitHub beats a CSR platform on extractability, loses everywhere else We included Stripe's `ARCHITECTURE.md` as a baseline: a plain markdown file served from GitHub's raw endpoint, which has no platform or chrome and is just plain text. It scored 42, tied with Document360 on a completely different profile. `ssrPass` is false (no HTML document at all), and the file has no `llms.txt`, no sitemap, no `.md`\-endpoint convention (it already _is_ `.md`, with no parallel HTML view to compare). But its `textRatio` is 0.996 and its noise ratio is zero. Answer quality cratered at 4/15 because `ARCHITECTURE.md` is a contributor doc, not an onboarding page. The takeaway isn't "ship raw markdown." It's that the floor for a real platform should sit higher than a single file, and four of them clear it comfortably. ## Robots.txt didn't discriminate Going in, we expected at least one platform to block AI bots. Not one did. Every platform we tested allows GPTBot, ClaudeBot, Claude-Web, PerplexityBot, Google-Extended, and CCBot at the root path: * Document360: all allowed * Docusaurus: all allowed * GitBook: all allowed * Jamdesk: all allowed * Mintlify: all allowed * ReadMe.com: all allowed * Stripe (raw MD on GitHub): no robots.txt on the raw-content host, so unrestricted by default Every platform scored the full 10/10: the six hosted platforms by explicitly allowing the crawlers, the raw GitHub file by having no robots rules to apply. The robots layer is effectively settled in the crawler's favor. The interesting decisions are happening one layer up, at the format and discovery layer. ## What this test gets wrong Some of these we can defend. Some we can't. All of them could change the rankings. **We shipped a scoring bug.** The headline correction in this post exists because v1.0 of our own script checked `llms.txt` at the wrong location. We caught it before publishing, but only barely, and only because the buggy result happened to flatter us. If a metric ever ranks its author first, that's the metric to audit hardest. The fixed probe is in the script below; the diff is in the repo. **We picked the test pages.** For each platform we chose one "deeper" content page (usually the quickstart) as the primary URL. Different page choices yield different scores. **Rubric questions are arbitrary.** "What is this product? How do I start? Where do I get help?" is a sensible developer-onboarding rubric, but it's one of many. Swap in "What's the rate limit? How do I authenticate? Where are the error codes?" and the platforms with strong API reference pages (Mintlify, ReadMe) probably extend their leads. **Tiny phrasing differences flip the rubric.** A one-point swing on a 15-point rubric becomes a 1.67-point swing on the total. The top four are close enough that this matters: the Jamdesk/ReadMe tie and Mintlify's one-point lead all live inside that margin. **We didn't include obvious other platforms.** Sphinx / Read the Docs, MkDocs Material, Hugo, Astro Starlight: none of these are in the test. We picked seven because they're the ones we get asked to compare against. A wider sweep would probably surface more platforms in the 70–85 range and compress the leaderboard. **The noise ratio is fragile.** We hash 200-byte chunks and count exact overlap. A single-byte difference (a request ID, a hashed asset URL, a timestamp) kills a match. Real shared chrome may be several times what we measured; the Docusaurus number (0.003) is probably under-counting. If you maintain one of these platforms and any of the above changes your numbers, we want the reproduction. That's what the GitHub issue template is for. ## Take Aways **Which docs platform is most AI-friendly?** On our 100-point rubric, Mintlify scored highest at 87 on June 1, 2026, on the strength of the best onboarding content in the test. Jamdesk and ReadMe.com tied for second at 85, and GitBook followed at 82. All four ship `llms.txt`, `llms-full.txt`, and a per-page `.md` endpoint on server-rendered HTML. Different weight schemes reorder the top four; see "About the weights." Re-run the script before you trust any of these numbers. **Does my docs platform need llms.txt?** Yes, if you want AI agents to find canonical content without crawling sidebars and footers. `llms.txt` is a small markdown file pointing at high-value pages; `llms-full.txt` is a single-file bundle of your docs in plain markdown. The [spec](https://llmstxt.org/?ref=cms.jamdesk.com) names the root path `/llms.txt` first but explicitly allows a subpath. Wherever you put it, link to the `.md` views of your best pages. **Is server-side rendering required for AI to read my docs?** Effectively yes. Most AI crawlers fetch plain HTTP and don't execute JavaScript. If your content only appears after hydration, the crawler sees an empty shell. That's why Document360 scored 0 on crawlability while serving 1.05 MB per page. **What is the .md endpoint convention?** Append `.md` to a docs URL and get back the plain markdown source. Mintlify, GitBook, ReadMe.com, and Jamdesk all support it. An LLM fetching `docs/quickstart.md` gets clean markdown instead of a few hundred KB of HTML chrome. **Are AI crawlers blocked from any docs platform?** Not in our test. The six hosted platforms allow the major AI crawlers (GPTBot, ClaudeBot, PerplexityBot, and others) at the root, and the raw GitHub file has no robots.txt at all. The interesting decisions are happening at higher layers: rendering pipeline, discovery files, and content structure. **How do I run the docs-ai-scorer script?** Clone [github.com/jamdesk/docs-ai-scorer](https://github.com/jamdesk/docs-ai-scorer?ref=cms.jamdesk.com), then run `node score-docs.mjs `. You'll get one line of JSON. Two URLs from the same site let the script compute the noise ratio. ## Limitations A few things this test does not cover, and one place where it was wrong. It _was_ wrong once already: the `llms.txt` probe bug described up top, which is exactly the kind of error an open script is meant to expose. We caught this one ourselves. The next one might come from a counter-run, and that's fine. We didn't test the writing UX of any platform. We didn't run Cursor or agent loops, just Claude Opus 4.8 as a grader on rendered HTML. JavaScript-discovered content (Algolia, Mendable, in-page search) is invisible to this test by design, because it's also invisible to most AI crawlers. But if your customers reach docs through an in-app agent that executes JS, the picture changes. We fetched every page with a generic browser-style User-Agent (`docs-ai-scorer/1.1`), not with `GPTBot` or `ClaudeBot`. Some platforms serve different HTML based on UA. We'll add a real AI-bot pass in v2 and report deltas. ## If you only do one thing this week Ship an `llms.txt`. It's about a dozen lines, takes ten minutes, and it's the single cheapest move on this entire rubric. Even Google is now considering llms.txt files in [Google Lighthouse scores](https://developer.chrome.com/docs/lighthouse/agentic-browsing/llms-txt?ref=cms.jamdesk.com). Put it at `/llms.txt` (and mirror it to your docs subpath if your docs live there), then link to the `.md` views of your highest-value pages. Below is the shape Jamdesk uses: ``` # Jamdesk Docs > Jamdesk is documentation software that publishes AI-readable output by default. ## Getting started - [Introduction](https://jamdesk.com/docs/introduction.md): What Jamdesk is and how it fits. - [Quickstart](https://jamdesk.com/docs/quickstart.md): Two files and a GitHub repo. - [How Jamdesk Works](https://jamdesk.com/docs/how-jamdesk-works.md): The full build-to-live pipeline. ## CLI - [CLI Overview](https://jamdesk.com/docs/cli/overview.md): Local preview, validation, deploy. ## AI - [llms.txt](https://jamdesk.com/docs/ai/llms-txt.md): How Jamdesk auto-generates the discovery files. - [MCP Server](https://jamdesk.com/docs/ai/mcp-server.md): Every site ships an MCP server. ``` Drop it at `/llms.txt`, link to the `.md` views of your highest-value pages, and you're done. The `.md`\-endpoint convention is the part that requires platform support. Server-side rendering takes work, cutting boilerplate noise takes design discipline, and writing a quickstart that answers five questions cleanly is its own craft. As this test shows, that last one is what separates the leaders. But shipping `llms.txt` is a Tuesday afternoon. ## Epilogue: we took our own advice Writing this post handed us a to-do list. The rubric graded Jamdesk's quickstart 12 out of 15 on answer quality. That one point was the gap to Mintlify, and the rubric was specific about where it went: three of the five onboarding questions lost points: where to get help, what the product actually is, and where to find the full command and feature list. So we fixed all three in our own docs: * **Where do I get help?** A dedicated "Need Help?" section: Help Center, live chat, and a support email. (This was the first fix, mentioned earlier.) * **What is this product?** The quickstart now opens by stating what Jamdesk is in one line, instead of jumping straight to deployment steps. * **Where's the feature/command list?** A new "Full Reference" section points to the component, CLI, and `docs.json` references in one place. The changes are live and the diff is public: [jamdesk-docs@989ae5d](https://github.com/jamdesk/jamdesk-docs/commit/989ae5d?ref=cms.jamdesk.com), rendered at [jamdesk.com/docs/quickstart](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com). The result: On a like-for-like re-grade (our own, which is exactly why it doesn't count yet), those three answers reach 3/3 each: 15/15 on answer quality, or **90 out of 100**, ahead of Mintlify's 87. --- ## Migrating from Mintlify to Jamdesk URL: https://www.jamdesk.com/blog/migrating-from-mintlify-to-jamdesk Published: 2026-05-11 *What the Jamdesk CLI rewrites when migrating a Mintlify docs repo, what to verify in the output, and the one component (snippets) still requiring a manual conversion.* If you're moving documentation from Mintlify to Jamdesk, the Jamdesk CLI handles most of the conversion automatically. This walks through what the [Mintlify migration](https://jamdesk.com/docs/setup/migration?ref=cms.jamdesk.com) does and what to verify in the output. ## Running the migration [Install the CLI](https://jamdesk.com/docs/cli/overview?ref=cms.jamdesk.com) globally: ```bash npm install -g jamdesk ``` Then, from the root of your existing Mintlify repo: ```bash jamdesk migrate ``` The migrate command handles everything for you. For example, it reads your `mint.json`, writes a new `docs.json` next to it, and rewrites component syntax across your MDX files in place to be Jamdesk compatible. Your `mint.json` isn't deleted, so you can diff against it afterward and remove it once your verify the output looks right. If you are not ready to overwrite your current docs, we recommend running this on a clean branch since the Jamdesk CLI rewrites files in place. ![Mintlify to Jamdesk migration](https://cms.jamdesk.com/content/images/2026/05/m1.png) ## What changes in the config The most visible change is the schema shift from `mint.json` to `docs.json`. A minimal Mintlify config looks like this: ```json { "name": "My Docs", "navigation": [ { "group": "Getting Started", "pages": ["introduction", "quickstart"] } ], "colors": { "primary": "#0D9373" }, "topbarLinks": [{ "name": "Blog", "url": "https://example.com/blog" }] } ``` After migration: ```json { "$schema": "https://jamdesk.com/docs.json", "name": "My Docs", "theme": "jam", "colors": { "primary": "#0D9373" }, "navbar": { "links": [{ "label": "Blog", "href": "https://example.com/blog" }] }, "navigation": { "groups": [ { "group": "Getting Started", "pages": ["introduction", "quickstart"] } ] } } ``` There are three transformations worth verifying by hand. First, the top-level `topbarLinks` array moves under `navbar.links`, and the field names change with it: `name` becomes `label`, `url` becomes `href`. If you also had a `topbarCtaButton`, it ends up in the same `navbar.links` array. The distinction between regular link and CTA button is no longer schema-level. Second, the `navigation` array becomes an object with a `groups` key. Each group's internal shape (`group` name plus `pages` array) is unchanged, so deeply nested nav structures don't need rewriting beyond this one wrapping. Third, a `theme` field is added at the top level, and a `$schema` reference is set so your editor validates the file going forward. Speaking of themes, the migration tool gives you recommendations on a compatible theme to switch to. For example, if you have the "mint" theme set in your `docs.json` file, the tool will recommend the "jam" theme as an alternative, and if accepted automatically switch you over. ## Component renames Most Mintlify components have direct, same-syntax equivalents in the [Jamdesk components](https://jamdesk.com/docs/components/overview?ref=cms.jamdesk.com). The standard set, including ``, ``, ``, ``, ``, ``, and the callout components (``, ``, ``), works without changes. Here are two renames handled automatically by the Jamdesk CLI: | Mintlify | Jamdesk | Notes | | --- | --- | --- | | `` | `` | `cols` prop works the same | | `` | `` | Props are identical | After migration, an API reference previously written as: ```mdx The unique identifier ``` now reads: ```mdx The unique identifier ``` ## Verifying the migration Before pushing, run a local preview with `jamdesk dev` and review the output. You'll get descriptive errors if there are any issues. The checklist is short: * Every page renders without an MDX compile error. * Navigation matches the original site's structure. * Internal links resolve. Broken links usually mean a page slug was remapped during the nav restructure. * Images and other static assets load. * Code blocks keep their syntax highlighting (the language tag survives migration, so verify anything custom). * Search indexes your content after the first build. For a site under fifty pages, this is generally a ten-minute review. On larger docs sets, the longest part will be verifying any custom React components still resolve under Jamdesk's MDX setup. Don't forget you and run `jamdesk validate` to do teh checks on your files. ## First deploy Once the diff looks right, push to your branch either by pushing to GitHub or using `jamdesk deploy`. Jamdesk picks up `docs.json` on commit and runs the build. From there the workflow is identical to any Git-based docs platform: push to the default branch, build runs, deploy completes, custom domain serves the new content. When the first build fails, the most common causes are a stray `` reference the CLI didn't catch, followed by `` props extended in custom forks of Mintlify components. Errors and warnings show clearly in the Jamdesk dashboard build log so you will be able to identify any final items to correct. --- ## Best GitHub Alternatives in 2026 URL: https://www.jamdesk.com/blog/best-github-alternatives Published: 2026-05-05 *GitHub has been getting a lot of bad press recently - some not deserved, but a lot is. If you look at Hacker News' front page, almost daily there is a report of GitHub having an outage or why such and such company is leaving Github. For example, Mitchell Hashimoto of Ghostty terminal, awesome tool by the way, recent posted about leaving Github with tears in his eyes. So, it seems to be the time to look into GitHub alternatives. Are they worth it, do they give you the same capabilities, and cost* GitHub has been getting a lot of bad press recently - some not deserved, but a lot is. If you look at Hacker News' front page, almost daily there is a report of GitHub having an outage or why such and such company is leaving Github. For example, Mitchell Hashimoto of Ghostty terminal, awesome tool by the way, [recent posted](https://mitchellh.com/writing/ghostty-leaving-github?ref=cms.jamdesk.com) about leaving Github with tears in his eyes. So, it seems to be the time to look into GitHub alternatives. Are they worth it, do they give you the same capabilities, and cost about the same? GitHub passed 180 million developers in 2025, adding a new account roughly every second ([GitHub Octoverse](https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/?ref=cms.jamdesk.com), 2025). They have about [90% of the source control market share](https://6sense.com/tech/source-code-management/github-market-share?ref=cms.jamdesk.com), so they are the gorilla and for most people it's the obvious choice, until it isn't. * Github is around [85% uptime](https://mrshu.github.io/github-statuses/?ref=cms.jamdesk.com) and even a site dedicated to [how many days without GitHub downtime](https://www.dayswithoutgithubincident.com/?ref=cms.jamdesk.com) - that is crazy. Most services talk about how many 9's they have, not how close we are to 90%. A fair point is their downtime has been increasing being of AI agents continually hammering their system. * Starting April 24, 2026, Copilot Free, Pro, and Pro+ accounts train on user code by default unless you opt out ([GitHub Blog](https://github.blog/news-insights/company-news/updates-to-github-copilot-interaction-data-usage-policy/?ref=cms.jamdesk.com), 2026). A bit on the sly, that one. One thing you need to be cognizant of is that a lot of source control integrations only support GitHub. It is changing and the frustration with GitHub mounts, but expect more often than not that "Click here to connect GitHub" is the only option. ## Why developers are leaving GitHub If a developer can't get their work done with a product, or they don't trust the service, they leave. Being down when you're trying to get work done is just bad. Yes, opting out of Copilot training is one checkbox. But silent default flips reveal the company's approach as not being user friendly. EU shops have a parallel concern: CLOUD Act exposure on a US-hosted forge sits awkwardly next to GDPR. So let's now look at some source control alternative. ## 1\. GitLab: the enterprise heavyweight ![GitLab logo, the all-in-one DevSecOps Git platform](https://cms.jamdesk.com/content/images/2026/04/gitlab-logo-2.svg) Of all the alternatives, [GitLab](https://about.gitlab.com/?ref=cms.jamdesk.com) is the only one that genuinely goes toe-to-toe with GitHub feature-for-feature. It's also the only public company on the list, which depending on how you feel about that is either a feature or a bug. If you want a hosted repo that won't make you give anything up, this is the way. The free tier covers 5 users with 400 CI minutes a month. Premium is $29/user/month with 10,000 CI minutes. Ultimate is custom-priced and bundles 50,000 CI minutes plus the full security suite ([GitLab pricing](https://about.gitlab.com/pricing/?ref=cms.jamdesk.com), 2026). And if you'd rather run it yourself, the self-managed Community Edition is free, no user cap. The price comparison with GitHub matters here. GitHub Team is $4/user/month and Enterprise is $21/user/month ([GitHub pricing](https://github.com/pricing?ref=cms.jamdesk.com), 2026), so on paper GitLab Premium looks expensive. But Ultimate bundles SAST, DAST, secret detection, dependency scanning, and container scanning at every paid tier — the kind of thing you'd otherwise pay Snyk or SonarQube for separately. Teams already cutting checks for those tools tend to come out ahead. Where GitLab gets harder is CI/CD. GitLab CI uses `.gitlab-ci.yml` with stages and DAG pipelines, and it is not Actions-syntax compatible. Porting a real-world Actions workflow is a rewrite, not a rename, and the pipeline syntax has a real learning curve - but if you use AI it should be easy. On the upside, Auto DevOps gives you one-command Kubernetes deploys, and the GitLab Duo Agent Platform GA'd in early 2026 with multi-agent CI fix flows that are actually useful, which is a rare praise to give an AI feature in 2026. The other catch is hardware. GitLab CE wants 4GB of RAM minimum if you're self-hosting — heavy compared to Gitea's 200MB — and a few of the compliance features still gate behind Ultimate. None of this is fatal for a regulated enterprise, but it might be fatal for a home setup. I have used GitLab for many years and find it to be awesome. I like the interface better than GitHub, which I now find cluttered. I would definitely choose GitLab if not for the unrelenting ubiquity of GitHub. ## 2\. Bitbucket: the Atlassian default ![Bitbucket logo, Atlassian's Git platform integrated with Jira](https://cms.jamdesk.com/content/images/2026/04/bitbucket-logo-2.svg) [Bitbucket](https://bitbucket.org/product/?ref=cms.jamdesk.com) really only makes sense if you already pay Atlassian. I mean their HTML meta title is "Bitbucket | Git solution for teams using Jira", which says it all. At $3/user/month for Standard and $6 for Premium, it's the cheapest commercial Git host on this list ([Atlassian pricing](https://www.atlassian.com/software/bitbucket/pricing?ref=cms.jamdesk.com), 2026). The free tier covers 5 users. So the price is right — Standard undercuts GitHub Team's $4/user, and you get pooled CI minutes on top. The actual reason to pick it **is** the Jira integration. Smart commits, branch-from-issue, deploy tracking inside the Jira board — nothing else here comes close if you're in the Atlassian ecosystem. If your engineering org runs on Jira, the constant tab-switching between GitHub and Jira just disappears. CI/CD is Bitbucket Pipelines: container-based steps from `bitbucket-pipelines.yml`. The unusual perk is that build minutes pool at the workspace level — a 50-user Standard workspace gets 125,000 build minutes shared across the whole team. That matters more than it sounds at scale, since GitHub bills minutes per user. The downside is direction. Bitbucket Server EOL'd in February 2024, so you're cloud-first by default. Data Center still exists for compliance shops from $2,300/year, but it clearly isn't where Atlassian invests anymore. If self-hosting is non-negotiable for you, this isn't your bag. I was previously a Bitbucket customer, admittedly over 5 years ago, and found it pretty good. The interface was clean and easy to use, more intuitive than GitHub at the time. I'd place GitLab above it overall, but for an Atlassian shop it's a no-brainer. Best fit: teams already living in Jira and Confluence, or cost-sensitive teams happy on cloud-only. ## 3\. Gitea: self-hosted, lightweight, Actions-compatible ![Gitea logo, the lightweight self-hosted Git forge](https://cms.jamdesk.com/content/images/2026/04/gitea-logo-2.svg) One Go binary at under 200MB of RAM. And SQLite ships built-in so you don't even need a separate database server. [Gitea](https://about.gitea.com/?ref=cms.jamdesk.com) happily lives on a $5 VPS, a Raspberry Pi 4, or the spare NAS in the corner of your office. MIT-licensed, no per-seat costs. The pricing is "free" — meaning your time and your hardware are the bill. Gitea Actions is the headline feature for anyone leaving GitHub. Drop your `.github/workflows/` into `.gitea/workflows/`, point an `act_runner` at Docker, and most basic workflows run unmodified, including most marketplace actions. We tested it: a 10-step Node CI workflow [for our docs platform](https://www.jamdesk.com/?ref=cms.jamdesk.com) ported to a Pi 4 with two YAML edits. Concurrency groups, environment protection rules, OIDC, and reusable cross-repo workflows still need adaptation, and a handful of marketplace actions assume GitHub-only API endpoints. A built-in package registry shipped in 1.17 (npm, Maven, container, PyPI), so most teams can drop a separate Artifactory or Nexus. The biggest weaknesses are community size and support. Forgejo (coming up next) forked Gitea in 2022 over governance disputes, and a chunk of the contributor base went with it. There's no native AI assist either, though third-party tools work fine against the standard Git protocols. And of course, self-hosting means you're the one getting paged when the disk fills up. So there's that.... The upside of that trade: your code isn't training anyone's model by default, Copilot or otherwise. After the April 2026 opt-out flip, that alone is reason enough for a lot of people to look at Gitea seriously. I've run Gitea on a Raspberry Pi for _personal projects_ and it has, frankly, never given me a reason to think about it. That's the highest praise you can give infrastructure. Pick it over GitHub when control matters more than convenience — when you'd rather own the box than rent the seat. Best fit: solo developers, homelabs, and small teams that want to `scp` the binary somewhere new and keep moving. ## 4\. Codeberg and Forgejo: the non-profit alternative ![Forgejo logo, the community fork of Gitea powering Codeberg](https://cms.jamdesk.com/content/images/2026/04/forgejo-logo-2.svg) [Codeberg.org](https://codeberg.org/?ref=cms.jamdesk.com) is a Berlin-based non-profit running Forgejo, the community fork of Gitea. The hosted service is free for FOSS projects and donation-funded; Forgejo itself is free to self-host, same lightweight hardware footprint as Gitea. CI/CD inherits from Gitea too and Forgejo Actions shares runner lineage and YAML compatibility with the same caveats. Codeberg.org runs Woodpecker CI for its hosted users. The reason to pick Codeberg over GitHub is domicile and regulations. It is EU-based, GDPR-native, no CLOUD Act exposure, and has an explicit anti-AI-training stance written into policy. Community-governed under a German non-profit, which means no acquisition risk. That last point is exactly why Gentoo moved here, and it's not a small thing — every other forge on this list could be bought tomorrow. There are a few things to note: * Codeberg.org is FOSS-only, so private commercial repos aren't an option, and there's no upgrade tier options. * Storage quotas apply. * Large project migrations have needed approval through Codeberg-e.V. requests since May 2025. * Hardware is slower than commercial peers, because there is no commercial peer paying the bill, and the anti-scraping stance means native AI assist isn't coming. If you're an EU developer who needs data sovereignty for real, not just on a compliance form, or a FOSS maintainer who doesn't want their code training Copilot look at Codeberg. If you need private commercial repos, self-host Forgejo on your own hardware instead, which has the same engine and no FOSS-only restriction. ## 5\. SourceHut: the minimalist hacker forge ![SourceHut logo, the minimalist email-driven Git forge](https://cms.jamdesk.com/content/images/2026/04/sourcehut-logo-2.svg) [SourceHut](https://sourcehut.org/?ref=cms.jamdesk.com) (sr.ht) is the contrarian pick on this list, and that's the point. No JavaScript required — the web UI works in Lynx — and the workflow centers on `git send-email` patches to mailing lists. Maintainers pay $2–10/month (financial aid available); contributors are free. So the price is fine. The price isn't really the question. builds.sr.ht runs full virtual machines across Linux distros and BSDs, not just Docker containers. If you ship cross-platform code, that's a big deal since there isn't anywhere else on this list you can run a CI job on FreeBSD or NetBSD without a heartache. Everything is fully free software, server included, and AI scraping is explicitly disallowed. The trade off is that you give up GitHub-style PR review entirely. Code review happens through emailed patches; `hub.sr.ht` provides a web patchset viewer but no inline review. If your team has never used a mailing-list workflow, the onboarding is steeper than anything else here. Best fit for kernel and BSD developers, and anyone who actually enjoys email patches (you know who you are!). ## GitHub alternatives compared Three of the five are free. Pick the cheapest option that fits your workflow. | Platform | Best for | Pricing | CI/CD | AI assist | | --- | --- | --- | --- | --- | | **GitLab** | Enterprise, security | Free; $29/user Premium; Ultimate custom | GitLab CI | GitLab Duo | | **Bitbucket** | Jira/Confluence shops | Free; $3/user/mo | Bitbucket Pipelines | Atlassian Intelligence + Rovo | | **Gitea** | Solo, homelab | Free (OSS, self-host) | Gitea Actions (YAML compat) | None native | | **Codeberg/Forgejo** | EU, FOSS, anti-AI | Free (OSS, self-host) | Forgejo Actions (YAML compat) | None (by design) | | **SourceHut** | Kernel/BSD, email | $2–10/mo | builds.sr.ht (full VMs) | None (by design) | What the table can't show: GitLab and Bitbucket bundle container, npm, Maven, and PyPI registries; Gitea and Forgejo have shipped one since 1.17; SourceHut deliberately doesn't. SAML/SSO sits in GitLab Premium, Atlassian Access, or a paid Forgejo module; Gitea ships OAuth2 free. GitLab and Gitea ship GitHub importers (repos, issues, PRs); SourceHut has none. Picking docs tooling alongside your forge? See our [best API documentation tools](https://www.jamdesk.com/blog/best-api-documentation-tools?ref=cms.jamdesk.com) breakdown. ## So What Should You Pick? Start with why you're leaving GitHub. If it's the 85% uptime, hosted GitLab solves it for most teams and self-managed GitLab or Gitea solve it for the rest — your uptime, your responsibility. If it's the Copilot-training default, Codeberg, Forgejo, Gitea, and SourceHut all explicitly don't train on your code; Bitbucket and GitLab make it a clear opt-in setting. If it's both, you're looking at a self-hosted Forgejo or Gitea instance. Classic decision tree. GitLab is the answer for most teams that want to leave but don't want to give anything up. The bundled security scanning pays for itself the moment you cancel a Snyk seat. The price tag seems large on paper, but match it line-for-line against GitHub Advanced Security on a per-seat plan. Bitbucket is an easy decision if you already live in Jira. The integration is better than anything else in this category, and at $3/user it's barely worth comparison-shopping. If you don't live in Jira, stay away. For self-hosting, Gitea is the path of least friction — your existing Actions workflows mostly just run, and the binary is small enough that backup is a `cp`. Forgejo gives you the same engine with stronger governance guarantees if you're worried about another acquisition. Codeberg sits one step further out: pick it if EU sovereignty or anti-AI-training is the actual reason you're here, not just a nice-to-have. SourceHut is its own thing. For the best [documentation software](https://www.jamdesk.com/?ref=cms.jamdesk.com) tool (it's us, so grain-of-salt), see [how Jamdesk compares](https://www.jamdesk.com/compare?ref=cms.jamdesk.com). --- ## Why Your API Docs Are Your Most Important Marketing Tool URL: https://www.jamdesk.com/blog/api-docs-marketing-tool Published: 2026-04-28 *My co-founder and I ran an API company for years. We built social media APIs, sold them to developers, and competed against companies with bigger teams and deeper VC pockets. We won more than we lost, and when I look back at why, it wasn't just the API. Plenty of competitors had comparable endpoints. And it wasn't our pricing. It was our API documentation. That sounds like a strange thing to say, but if you've ever sold a developer tool, you know exactly what I mean. Developers don't sit throug* My co-founder and I ran an API company for years. We built social media APIs, sold them to developers, and competed against companies with bigger teams and deeper VC pockets. We won more than we lost, and when I look back at why, it wasn't just the API. Plenty of competitors had comparable endpoints. And it wasn't our pricing. It was our API documentation. That sounds like a strange thing to say, but if you've ever sold a developer tool, you know exactly what I mean. Developers don't sit through demos and they don't read your homepage copy. They open your API docs, try to make a call, and decide in about ten minutes whether your product is worth their time. Their BS meter will have them running if your docs aren't solid. ## Three Pillars That Built an API Business At my previous company, we focused on three pillars: the API itself, our customer support, and our documentation. * The [API](https://www.jamdesk.com/blog/what-is-an-api?ref=cms.jamdesk.com), of course, needed to be awesome, fully featured, stable, and meet our customers' need. * For support we never used AI and always had a real person helping users - better to delay and answer than some crappy AI response. * And finally the docs need to be amazing because they were the first impression developers had about us. The docs were treated as a product. As a self-fulfilling prophesy, because we focus so much on writing good docs, they ranked well on Google. We didn't do keyword research or hire an SEO agency to SEO optimize the docs, but rather we wrote content that answered the actual questions developers were asking. Google mostly rewards that. Developers would find us through a search query, land on our docs, and realize the API did what they needed, fully by-passing out marketing homepage. During sales calls, leads regularly told us how clear and well-written our API documentation was. We wrote everything ourselves, before AI writing tools existed, so no GPT drafts, no autocomplete, no "generate docs from code" shortcuts. Every sentence was deliberate, crafted by our team who understood the API because they built it. That discipline forced us to actually think about what developers needed to know, in what order, and what would confuse them. You can't shortcut that understanding with a prompt. That effort showed, and developers noticed. The key point isn't about not using AI to write you docs, but rather the content needs to be excellent. The competitive advantage wasn't that we _had_ docs. Everyone has docs. Ours were better because we treated them as a product, not an afterthought someone threw together before launch. The numbers bear this out across the industry. [Postman's 2025 State of the API Report](https://www.postman.com/state-of-api/2025/?ref=cms.jamdesk.com) found that 82% of organizations have adopted an API-first approach, up from 66% in 2023, and 65% now generate direct revenue from their API programs. If your API is a revenue line (and increasingly, that's the case), your documentation is the sales team working 24/7. ## The Feedback Loop Powered Our Docs We updated our documentation daily - every single day! The system was simple: a customer asks our support team a question. We answer them. Then we ask ourselves, "Would someone else ask this too?" If the answer was yes (and it almost always was), we updated the docs before the end of the day. Sometimes that meant clarifying a confusing parameter description. Sometimes it meant writing an entirely new section. Over months, this compounds. Your docs absorb every real question your users have and fine-tunes everything. They become a living document that anticipates confusion before it happens. The next developer who hits that same issue just finds the answer already there. As a side note, no matter how good your docs are you'll still have users who rather ask someone than refer to docs - and that is ok - it is what the pillar 2 on support is all about. You can think about this being a product management practice applied to documentation. Most companies don't do it because docs aren't owned by product. They're owned by nobody, sitting in some repo that engineering updates when they remember. When docs are nobody's job, they're nobody's priority. ### The Cost of Getting It Wrong ![The Docs Feedback Loop — a circular diagram showing how daily documentation updates create a compounding advantage through customer questions, support answers, doc updates, fewer repeat questions, faster onboarding, and more conversions](https://cms.jamdesk.com/content/images/2026/04/feedback-loop-2.webp) The cost of getting this wrong is measurable. [DX research](https://getdx.com/blog/developer-documentation/?ref=cms.jamdesk.com) found that developers spend 3 to 10 hours per week searching for information that should already be documented. For a 100-person engineering team, that's 300 to 1,000 hours lost every week, the equivalent of 8 to 25 full-time engineers doing nothing but hunting for answers. A 5-point improvement in Developer Experience Index from better documentation translates to roughly 5,000 recovered hours annually, or about $500,000 in productivity gains. What about AI agents? More on that later. You know what bad docs look like. We all do. The quickstart guide that was written for version 1.0 and [never updated](https://www.jamdesk.com/blog/why-static-and-outdated-docs-are-holding-your-product-back?ref=cms.jamdesk.com). Response schemas that don't match what the API actually returns. Error codes with no explanation. Code examples that throw exceptions when you copy-paste them. No versioning, so you can't tell if you're reading docs for the current release or something three years old. Every one of those failures is a developer who gave up and went to your competitor. ![How Developers Learn About Your API in 2025 — horizontal bar chart showing Technical Documentation leads at 67.8 percent, followed by Online Resources, Stack Overflow, Videos, AI Tools, Blogs, and Online Courses](https://cms.jamdesk.com/content/images/2026/04/learning-resources.webp) ## Why Bad Docs Lose, Good Docs Win Think about how a developer actually evaluates your API. They don't read your marketing landing page. They might glance at pricing, mostly to check if there's a free tier or if their company will cover it. But the first real interaction is your technical docs. [Postman's 2025 report](https://www.postman.com/state-of-api/2025/?ref=cms.jamdesk.com) found that 93% of API teams struggle with collaboration challenges, including poor discovery and outdated documentation. Nearly every team shipping an API knows their docs aren't good enough, but they ship them anyway. Can I find the endpoint I need? Are the parameters documented clearly? Is there a working code example I can run right now? Does the response match what the docs say it'll return? Can I try this without writing a full integration first? That last question matters more than most companies realize. An interactive API playground (where a developer can fill in parameters and send a real request from inside your docs) compresses the evaluation from hours to minutes. They don't need to set up a project, install an SDK, or write boilerplate. They click "Try it," see a response, and know whether your API does what they need. ![How Developers Actually Evaluate Your API — flow diagram showing developers skip the homepage and pricing page, go straight to API docs and the playground, then either integrate or close the tab](https://cms.jamdesk.com/content/images/2026/04/evaluation-path.webp) If a developer can't make a successful API call during their evaluation window, you've lost them. You'll never know. They won't email you or fill out a feedback form. They'll just close the tab and try the next option on their list. The API economy is now worth an estimated $20 billion and growing at double-digit rates annually ([Global Information Inc](https://www.giiresearch.com/report/tbrc1984908-application-programming-interface-api-economy.html?ref=cms.jamdesk.com), 2026). Competition for developer attention is fierce. Your API documentation is often your only shot at a first impression. Make sure it's not the reason you're losing deals. ![API-First Adoption Is Accelerating — line chart showing growth from 66 percent in 2023 to 74 percent in 2024 to 82 percent in 2025](https://cms.jamdesk.com/content/images/2026/04/api-adoption.webp) ## AI Changes Everything? This is the part where you might expect me to say "AI changes everything." It does, but not in the way you might think. [Gartner predicts](https://www.gartner.com/en/newsroom/press-releases/2024-03-20-gartner-predicts-more-than-30-percent-of-the-increase-in-demand-for-apis-will-come-from-ai-and-tools-using-llms-by-2026?ref=cms.jamdesk.com) that more than 30% of the increase in demand for APIs will come from AI and tools using large language models by 2026. MCP — Anthropic's Model Context Protocol for connecting AI agents to external tools — exploded from 100,000 to over 97 million monthly SDK downloads in just 15 months ([Pento](https://www.pento.ai/blog/a-year-of-mcp-2025-review?ref=cms.jamdesk.com), 2025) and it is well beyond that today. AI agents aren't a future thing. They're hitting your API docs right now. ### What Each Audience Needs The practical split looks like this: | | Human Developers | AI Agents | | --- | --- | --- | | **Format** | Beautiful, well-designed pages | Structured markdown, `llms.txt`, MCP | | **Priority** | Working code examples, clear navigation | Machine-parseable content, schema definitions | | **Evaluation** | "Can I make a call in 10 minutes?" | "Can I understand this API programmatically?" | | **Decision** | Signs the contract | Recommends the API to the developer | | **Trust signal** | Professional design, playground, search | Consistent formatting, complete coverage | But I disagree with the "AI-first" crowd on one point: the human still makes the buying decision even if an AI recommends a product. A CTO doesn't let an AI agent pick the company's payment processor or communications API. A lead developer doesn't blindly integrate whatever Claude or Copilot suggests. They verify and read the docs themselves. And the data backs this up. The [2025 Stack Overflow Developer Survey](https://survey.stackoverflow.co/2025/?ref=cms.jamdesk.com) found that 46% of developers actively distrust AI tool accuracy. Only 3% say they "highly trust" it. When an AI agent recommends your API, the developer's next step is opening your documentation to verify the recommendation. If your docs are confusing, outdated, or ugly, the AI's endorsement means nothing. So you need both. You need machine-readable formats: [`llms.txt` files](https://jamdesk.com/docs/ai/llms-txt?ref=cms.jamdesk.com), [MCP servers](https://jamdesk.com/docs/ai/mcp-server?ref=cms.jamdesk.com), and [raw markdown endpoints](https://jamdesk.com/docs/ai/markdown-source?ref=cms.jamdesk.com). If you're not sure what that looks like in practice: ```bash $ curl https://your-docs.example.com/llms.txt # Your Product Docs > Documentation for the Acme API - [Authentication](/auth): API key setup and OAuth2 flows - [Users](/api/users): Create, update, and list users - [Webhooks](/webhooks): Event subscriptions and payloads ... ``` That's what AI agents read instead of crawling your site page by page. These are table stakes now. Without them, AI agents can't recommend what they can't read. But you also need beautiful, well-organized, human-readable docs for the person who signs the contract. The docs need a professional design, logical navigation, working code examples, and an API playground where they can try a real request in 30 seconds. One without the other is half a strategy. Yet [Postman's 2025 report](https://www.postman.com/state-of-api/2025/?ref=cms.jamdesk.com) found that only 24% of developers currently design APIs with AI agents in mind. That's a massive gap. The companies that close it first will have a compounding advantage as AI-assisted development becomes the norm. ## Your Docs Are Your Sales Team Your documentation is doing more marketing work than your marketing team. Or it should be. The operational discipline matters more than any tool: treat docs as a product, update them daily based on real user questions, and own them at the product level. In 2026 they serve two audiences, developers and AI agents, and most companies are only building for one. Your best marketing asset might be the one your marketing team never touches. ## How We Built Jamdesk Around These Lessons Everything I described is why we built [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com). Same philosophy: docs live in Git, deploy on merge, with a built-in [API playground](https://jamdesk.com/docs/api-reference/playground?ref=cms.jamdesk.com) and auto-generated [`llms.txt`](https://jamdesk.com/docs/ai/llms-txt?ref=cms.jamdesk.com). You can see it working on [our own OpenAPI example page](https://jamdesk.com/docs/api-reference/openapi-example?ref=cms.jamdesk.com). If your docs aren't pulling their weight, [give it a try](https://dashboard.jamdesk.com/?ref=cms.jamdesk.com). --- ## The Definitive API Documentation Pricing Comparison [2026] URL: https://www.jamdesk.com/blog/the-definitive-api-documentation-pricing-comparison-2026-2 Published: 2026-04-20 *What eight platforms actually cost when you factor in seats, AI add-ons, and the features you will need six months from now. Executive Summary API documentation platforms have reached broad feature convergence. Most established players now offer OpenAPI rendering, markdown-based editing, custom domains, and some form of AI-powered search or chat. Yet behind this surface-level similarity, pricing structures diverge sharply. Two platforms offering nearly identical capabilities will produce twel* **What eight platforms actually cost when you factor in seats, AI add-ons, and the features you will need six months from now.** ## Executive Summary API documentation platforms have reached broad feature convergence. Most established players now offer OpenAPI rendering, markdown-based editing, custom domains, and some form of AI-powered search or chat. Yet behind this surface-level similarity, pricing structures diverge sharply. Two platforms offering nearly identical capabilities will produce twelve-month invoices differing by tens of thousands of dollars. The gap between an advertised starting price and the actual cost a team pays after accounting for seats, AI add-ons, analytics tiers, and branding removal has become a challenge for engineering leaders evaluating documentation tooling in 2026. This report provides an apples-to-apples cost analysis of eight documentation platforms: Jamdesk, Mintlify, GitBook, ReadMe, Redocly, Stoplight, Document360, and Archbee. We evaluate each platform across two real-world scenarios. Scenario A models a small startup with one documentation site and three editors. Scenario B models a scaling organization with five documentation sites and thirty editors. Both scenarios hold constant a set of features that most production documentation deployments require within their first year: a custom domain, AI-powered chat or search, usage analytics, branding removal, and OpenAPI specification support \[1\]. The findings are significant. For a three-person team running a single documentation site with the full feature set described above, twelve-month (annual) total costs range from $348 (Jamdesk Pro) \[2\] to $6,600 (ReadMe with add-ons) \[3\]. For a thirty-person team managing five sites, costs range from $1,068 per year on Jamdesk Pro with extras \[2\] to over $39,000 per year on ReadMe \[4\]. Platforms that appear affordable at first glance frequently gate the features teams need behind higher tiers or paid add-ons. AI capabilities have emerged as the most aggressively monetized feature category, with several vendors charging $150 per month or more for AI chat functionality on top of already-premium base plans \[5\]. The purpose of this analysis is to give engineering managers, developer experience leads, and technical writers the data needed to forecast real costs over a twelve-month horizon rather than making purchasing decisions based on landing-page pricing alone. ![Horizontal bar chart comparing 12-month total costs across 9 API documentation platforms for Scenario A](https://cms.jamdesk.com/content/images/2026/04/chart-1-hero-v2.png) A note on billing cadence: All prices in this report use monthly billing rates unless otherwise noted. Many vendors offer discounts of 15 to 20 percent for annual commitments, but monthly billing represents the true list price and we find it usually the default option when a company subscribes to a new SaaS. Where annual pricing differs materially, we note both figures. ## Methodology All pricing data in this report was collected from vendor pricing pages and public documentation between March 10 and March 23, 2026, and re-verified in April 2026 \[6\]. Mintlify's pricing was re-verified in July 2026 after the vendor replaced its $300-per-month Pro tier with a flat $540-per-month Pro plan (no per-seat charges) and credit-metered AI; Mintlify figures in the tables and text reflect the July 2026 structure, while charts generated from the spring dataset may still show the earlier Mintlify totals. Jamdesk's team-member pricing was also re-verified in July 2026: team members are now unlimited on every plan at no extra charge. Where vendors do not publish pricing (as with Document360, which moved to quote-based pricing in late 2024 \[7\]), we note the absence and provide estimated ranges drawn from third-party review platforms and industry analyst reports. We constructed two evaluation scenarios to reflect common team configurations. Scenario A models a small startup or early-stage team: one documentation site with three editors. Scenario B models a scaling organization: five documentation sites with thirty editors distributed across them. Both scenarios assume the team requires a core set of capabilities within the first twelve months: a custom domain with SSL, AI-powered chat or search for end users, a usage analytics dashboard, removal of the vendor's branding from the published site, and OpenAPI specification import or rendering \[8\]. For AI usage estimates, we assume moderate consumption: 500 AI messages per month for Scenario A and 3,000 AI messages per month across all sites for Scenario B. These figures represent roughly five to seven AI queries per user per business day, a conservative but realistic estimate for teams with active API consumers. Total cost of ownership is calculated as the sum of base subscription fees, per-seat charges, AI feature add-ons, AI overage charges, and analytics add-ons over a twelve-month period. All prices reflect monthly billing unless otherwise stated. We will note that Docusaurus was considered but excluded from this comparison. As a free open-source static site generator, it does not include AI-powered search, analytics, managed hosting, branding removal, or customer support, and does not meet the minimum feature set defined in our scenarios \[9\]. ## The Pricing Environment in 2026 ### How We Got Here The API documentation market has gone through three distinct phases in the past decade. The first phase was dominated by static site generators. Tools like Sphinx, Jekyll, Gatsby, and eventually Docusaurus gave engineering teams full control over their documentation output at the cost of significant setup and ongoing maintenance time. These tools were free in licensing terms, but expensive in engineering hours, and they produced documentation sites that often lacked interactive features like API playgrounds, search, and analytics \[10\]. The second phase, roughly 2018 through 2023, saw the rise of managed documentation platforms. GitBook, ReadMe, Mintlify, and others offered hosted, no-configuration solutions that traded some customization flexibility for dramatically faster time-to-publish. These platforms competed primarily on developer experience, design quality, and integration depth. Pricing was generally straightforward during this period: most platforms charged a flat monthly fee or a simple per-seat rate, and the feature sets across tiers were relatively transparent \[11\]. The third and current phase began in 2024 when large language models became practical to deploy as documentation assistants. Nearly every managed platform added some form of AI-powered search, chat, or content generation capability within an eighteen-month window. The technical cost of serving AI queries (inference compute, embedding generation, vector storage) gave vendors a defensible rationale for creating new pricing tiers and add-on charges specifically around AI features \[12\]. A market converging on feature parity suddenly found a new axis of differentiation: not whether a platform offered AI, but how much a team would pay to use AI. This shift matters because AI-powered documentation search is moving from a differentiator to a baseline expectation. The 2025 Stack Overflow Developer Survey reports that 84 percent of developers use or plan to use AI tools in their development process, and that more than half of heavy AI users rely on AI to search for answers and troubleshoot issues \[13\]. Platforms that gate this capability behind premium tiers or usage-based add-ons impose an ongoing cost on meeting user expectations, one that compounds as documentation traffic grows. ### Documentation as AI Infrastructure The pricing conversation sits within a broader shift in what documentation has become. Documentation in 2026 is no longer a static support asset that users read passively. Documentation has evolved into a knowledge layer, a dataset that AI systems consume, interpret, and serve back to users through chat interfaces, code assistants, and automated workflows. When an AI agent retrieves incorrect or outdated information from your documentation, users will rightfully be disappointed in your product and will likely stop using the product. This means the structured formats a documentation platform supports are no longer optional technical niceties and are core to your infrastructure. Three formats have emerged as essential for modern AI-native documentation: 1. OpenAPI and Swagger specifications provide a machine-readable blueprint for APIs. Platforms that synchronize these directly with the codebase automatically generate interactive references, ensuring the AI's source of truth stays aligned with the production environment. Every platform in this analysis supports OpenAPI to some degree, but the depth of integration (automatic sync versus manual import) varies significantly. 2. llms.txt is a standard that provides a dedicated, simplified text-only entry point for LLM consumption. AI tools ingest core product functionality through this file without the noise of HTML boilerplate or UI elements. Of the eight platforms analyzed, only Jamdesk (auto-generated) \[2\], GitBook (auto-generated, including llms-full.txt) \[23\], and ReadMe (included on free tier) \[4\] support llms.txt natively. The remaining six platforms require manual implementation or do not support the format at all. 3. Model Context Protocol (MCP) and Command Line Interfaces (CLIs) represent the next evolution beyond static exports. Unlike llms.txt, which is a file that AI tools fetch on demand, MCP is a live connection protocol that exposes documentation as a real-time data source for AI tools during active user sessions. CLIs serve a different but complementary role. A documentation CLI lets developers preview docs locally, validate OpenAPI specs, sync content from the command line, and integrate documentation workflows into CI/CD pipelines without leaving the terminal. For teams that treat documentation as code, a CLI is the primary interface for building, testing, and deploying docs. Several platforms now ship CLIs: Jamdesk, Mintlify, ReadMe, Redocly, and Stoplight all offer command-line tools with varying levels of functionality \[2\]\[14\]\[4\]\[17\]\[18\]. The risk these formats address is Knowledge Drift, the divergence between code and documentation that occurs when synchronization is manual or delayed. When code and docs diverge, AI assistants produce hallucinations. Automating the synchronization between repositories and documentation through Git-based workflows is the primary defense. This is why docs-as-code platforms that store content in Git repositories and deploy through CI/CD pipelines have a structural advantage over platforms that rely on web-based editors with manual publishing workflows. The implication for pricing evaluation is direct: the cost of AI features should be weighed against the operational cost of documentation that AI tools cannot read or trust. ![AI readiness matrix comparing 9 documentation platforms across 5 AI infrastructure features](https://cms.jamdesk.com/content/images/2026/03/chart-2-ai-readiness.png) ### Four Pricing Models Across the eight platforms analyzed, we identified four distinct pricing models. Understanding which model a vendor uses is essential for forecasting costs accurately, because the same nominal monthly price will produce vastly different twelve-month totals depending on how the model scales with team size and feature requirements. Flat rate pricing charges a single monthly fee for a core configuration regardless of usage. Jamdesk is the clearest example. The Pro plan costs $29 per month and includes one documentation project with unlimited team members, no AI usage fees or caps, and no feature gating across analytics, branding removal, or custom domains \[2\]. Extra projects are priced as linear add-ons rather than as tier upgrades. This model offers strong budget predictability for small teams but is uncommon in the current market. Tiered feature gating uses multiple plan levels where specific features are available only at higher price points. ReadMe and Mintlify both employ this approach. ReadMe's free Starter tier provides basic documentation hosting with lightweight AI features, but branding removal, branching, reviews, and custom MDX require the Pro tier at $300 per month on monthly billing ($250 per month on annual billing), and the full Ask AI agent requires an additional $150 per month add-on \[4\]. Mintlify's free Starter tier includes no AI credit allocation. Accessing the AI assistant requires jumping to the $540 per month Pro plan (monthly billing) with no intermediate option \[14\]. The risk with tiered gating is that teams sign up for an affordable entry tier, then find within months that the features they need sit one or two tiers higher. Per-seat plus per-site stacking multiplies costs across two independent dimensions. GitBook is the primary example: teams must purchase both a Site Plan (ranging from free to $299 per site per month on monthly billing \[15\]) and a User Plan ($15 per user per month \[16\]). A three-person team running one Premium site with user seats pays $79 plus three times $15, or $124 per month. If that team needs branding removal (available only on the Ultimate site plan at $299 per month), the cost jumps to $344 per month for a single site \[15\]. Adding a second site doubles the site plan component. Per-user pricing scales linearly with team size. Redocly and Stoplight both follow this model, though with different base structures. Redocly's Pro plan charges $28 per user per month on monthly billing \[17\], while Stoplight bundles a set number of users into each tier and charges $14 to $27 per additional user depending on the plan \[18\]. Per-user pricing is transparent and predictable for small teams, but costs escalate as organizations grow. | Platform | Pricing Model | Monthly Billing Price | Key Cost Multiplier | | --- | --- | --- | --- | | Jamdesk | Flat rate | $29/mo \[2\] | Extra project $15/mo; unlimited team members included | | Mintlify | Tiered feature gating + metered AI | $540/mo Pro \[14\] | AI credits: 10,000/mo included, then $0.01/credit. No per-seat fees | | GitBook | Per-seat + per-site stacking | $79 to $299/site/mo \[15\] | \+ $15/user/mo \[16\] | | ReadMe | Tiered feature gating + add-ons | $300/mo Pro \[4\] | Ask AI $150/mo. Dashboard $100/mo | | Redocly | Per-user | $28/user/mo Pro \[17\] | $66/user/mo Enterprise | | Stoplight | Per-user (bundled tiers) | $56 to $453/mo \[18\] | Extra seats $14 to $27/user/mo | | Document360 | Quote-based (opaque) | Not published \[7\] | Unknown, requires sales engagement | | Archbee | Tiered + per-contributor | $100 to $400/mo \[20\] | Add-ons: AI $20/mo, Analytics $80/mo \[22\] | ![Scatter plot mapping 9 documentation platforms by cost predictability and feature completeness](https://cms.jamdesk.com/content/images/2026/03/chart-3-quadrant-map.png) ## Platform-by-Platform Pricing Analysis ### Jamdesk Jamdesk uses a flat-rate pricing model built around a single documentation project and unlimited team members. The Pro plan costs $29 per month and includes AI-powered chat and search, analytics with geographic heatmaps, white labeling with complete branding removal, custom domain with SSL provisioning, over 25 MDX components, OpenAPI specification support, automatic llms.txt generation, custom CSS injection, full API access, syntax highlighting for more than 100 languages, password protection for docs, and priority support \[2\]. There are no AI usage caps and no analytics add-ons to purchase separately. Team members are unlimited at no extra charge, and additional documentation projects are $15 per month each. A 14-day free trial is available. | Tier | Monthly Price | What You Get | | --- | --- | --- | | Free Trial | $0 (14 days) | Full platform access | | Pro | $29/mo | Core features, 1 project, unlimited team members, unlimited AI usage (extra project $15/mo) | | Pro (Annual) | ~$24/mo | 17% discount on annual billing | | Enterprise | Custom | SSO/SAML, multiple sites, dedicated account manager, SLA | The unlimited-seat policy is worth examining. On most competing platforms, adding a fifth or tenth editor triggers a tier-level cost increase, often $15 to $20 per user per month. Jamdesk charges nothing per seat. A solo developer and a thirty-person team pay the same $29 per month for the Pro plan \[2\]. This makes budgeting straightforward: the line item stays flat no matter how many editors join. AI capabilities highlight another structural difference. Where competitors meter AI interactions (charging per message after a monthly cap or locking AI features behind premium add-ons), Jamdesk bundles AI chat and AI-powered search into the base plan with no usage ceiling \[2\]. A team fielding 1,000 AI queries per month on a metered platform faces hundreds of dollars in overage charges. On Jamdesk, that same usage adds nothing beyond the $29 base. Analytics follow the same pattern. Geographic heatmaps, page-level engagement data, and search analytics are part of the Pro plan \[2\]. Competitors frequently reserve analytics for business or enterprise tiers. The Enterprise tier adds SSO and SAML authentication, the ability to manage multiple documentation sites under one account, a dedicated account manager, and a guaranteed SLA \[2\]. Pricing is custom and negotiated directly. Annual billing reduces the effective monthly cost by 17 percent, bringing the Pro plan to approximately $24.17 per month \[2\]. Over twelve months, that totals $290. ### Mintlify Mintlify has built a polished documentation platform with strong developer experience, but a pricing gap affects purchasing decisions for growing teams. The plan lineup: Starter (free), Pro ($540 per month on monthly billing, $450 per month on annual billing), and Enterprise (custom pricing) \[14\]. There is nothing between $0 and $540. The moment a team outgrows the Starter plan's constraints, the cost jumps by $540 per month. | Tier | Monthly Billing | Annual Billing | Workspace Members | AI Credits | | --- | --- | --- | --- | --- | | Starter | $0 | $0 | 5 max | None included | | Pro | $540/mo | $450/mo | No per-seat pricing | 10,000/mo (then $0.01/credit) | | Enterprise | Custom | Custom | Custom | Custom | The Starter plan caps the workspace at five members, includes no AI credit allocation, and does not include preview deployments \[14\]. For a solo developer or a very small team experimenting with the platform, these limitations are manageable. But the moment a sixth person needs workspace access, or the team wants the AI assistant, the only option is the Pro plan at $540 per month (monthly billing). Pro includes preview deployments, platform analytics, password protection for documentation sites, and grammar and spelling checks \[14\]. The AI assistant and writing agent activate at this tier, metered in credits: 10,000 credits per month are included, and each additional credit costs $0.01 \[14\]. Mintlify no longer charges per editor seat; the Pro price is flat regardless of team size \[14\]. The credit meter deserves scrutiny. 10,000 credits per month sounds generous in the abstract, but the assistant, the writing agent, and automations all draw down the same pool, and agent-heavy workflows burn through it quickly. Every credit beyond the allocation costs $0.01, so a team that runs 25,000 credits in a month pays $540 for the Pro base plus $150 in overage, totaling $690 per month \[14\]. Even without overage, twelve months of Pro on monthly billing comes to $6,480. ### GitBook GitBook's pricing model is among the most complex in the space. Buyers must combine two separate plan types: a Site Plan that governs what the published documentation site does, and a User Plan that governs what each team member does within the editor \[15\]\[16\]. Many prospective buyers evaluating GitBook's pricing page for the first time miss this dual-plan structure, leading to cost surprises when the invoice arrives. | Plan Type | Tier | Monthly Billing | What Does This Control | | --- | --- | --- | --- | | Site Plan | Free | $0 | gitbook.io subdomain only | | | Premium | $79/site/mo | Custom domain, AI search, analytics, PDF exports | | | Ultimate | $299/site/mo | Site sections, cross-doc search, visitor auth, logo removal | | User Plan | Paid | $15/user/mo | Team collaboration, permissions, AI writing/editing | Annual billing reduces site plans to $65 (Premium) and $249 (Ultimate) per site per month, and user plans to $12 per user per month \[15\]\[16\]. The stacking effect drives cost escalation. A three-person team that needs AI-powered search on their documentation site pays the Premium Site Plan ($79 per month) plus three User Plans (3 times $15, or $45 per month), totaling $124 per month for a single documentation site \[15\]\[16\]. That figure is competitive until the team needs branding removal. Removing the GitBook logo requires the Ultimate Site Plan at $299 per month, which pushes the same three-person team to $344 per month \[15\]. Multi-site deployments amplify the cost further. An organization maintaining five documentation sites at the Ultimate tier with thirty users would pay $299 times five sites plus $450 in user fees, totaling $1,945 per month \[15\]\[16\]. Each additional site adds another $299 per month at the Ultimate tier. The dual-plan structure introduces cognitive overhead during the evaluation process and creates scenarios where a buyer must upgrade two separate plan dimensions simultaneously to access a single feature. AI search requires a Premium or Ultimate Site Plan, while AI editing requires a paid User Plan \[15\]\[16\]. A team wanting both AI capabilities must pay for upgrades on both axes. ### ReadMe ReadMe positions itself as a developer hub platform, combining API documentation with developer analytics and interactive API exploration. The pricing structure layers a three-tier plan system (Starter, Pro, Enterprise) on top of two significant add-ons, creating a model where the advertised tier price often represents only a fraction of the total monthly cost \[4\]. | Tier | Monthly Billing | Annual Billing | Key Additions Over Previous Tier | | --- | --- | --- | --- | | Starter | $0 | $0 | Custom domain, bidirectional sync, interactive API reference, markdown editor, AI Dropdown, LLMs.txt, MCP Server | | Pro | $300/mo | $250/mo | Remove ReadMe logo, invite teammates, branching and reviews, private docs, landing page, changelog, custom MDX components, reusable content, CSS/HTML, Ask AI Lite, Agent Owlbert, AI Doc Linting | | Enterprise | Custom | $3,000+/mo | Multiple combined projects, user roles and access control, SSO/OAuth, audit logs, dedicated support, Docs Audit, global lint rules | | Add-On | Monthly Price | What Does This Include | | --- | --- | --- | | Ask AI | $150/mo | Full Ask AI agent on top of the Ask AI Lite included with Pro, plus AI analytics and model selection | | Developer Dashboard | $100/mo base | 5M API logs included, then $10 per additional 1M logs | Branding removal is available starting on the Pro tier at $300 per month on monthly billing ($250 per month on annual billing) \[4\]. This is a $300 per month jump from the free Starter tier. For many teams, the primary driver for upgrading is simply the need to remove ReadMe's logo and unlock branching, reviews, and custom MDX components. The add-on layer adds further cost. The Ask AI add-on at $150 per month unlocks the full Ask AI agent on top of the Ask AI Lite included with Pro, plus AI analytics and model selection \[4\]. The Developer Dashboard adds $100 per month for API log analytics \[4\]. The compounding effect: a team that needs branding removal, the full Ask AI agent, and developer analytics pays $300 for Pro, $150 for Ask AI, and $100 for Developer Dashboard, totaling $550 per month on monthly billing \[4\]. Over twelve months, that amounts to $6,600 annually. ### Redocly Redocly has built its reputation on an OpenAPI-first philosophy, using the popular open-source Redoc renderer as the foundation for a commercial documentation platform. The pricing is per-seat with the full "Realm" product suite (Redoc, Revel, Reef) \[17\]. | Tier | Monthly Billing | Annual Billing | Includes | | --- | --- | --- | --- | | Pro | $28/seat/mo | ~$25/seat/mo | 1 project, 100 pages, custom domain, "Try It" API console | | Enterprise | $66/seat/mo | ~$58/seat/mo | 500 pages, SSO, guest SSO, RBAC, AI search, remote content | | Enterprise+ | Custom (yearly only) | Custom | Data residency, procurement forms, security questionnaires | For a three-person team on the Pro tier, the monthly cost comes to $84 on monthly billing \[17\]. At the Enterprise level with AI search and SSO, the same team pays $198 per month. The per-user model means costs scale linearly and predictably with team size. The trade-off is scope. Redocly is fundamentally an API reference rendering tool, and while the rendering quality is strong, the platform has limitations as a full documentation solution. The Pro tier lacks AI search capabilities and branding removal options. Teams needing those features must move to the Enterprise tier at $66 per seat per month \[17\]. ### Stoplight Stoplight approaches documentation from the API design side of the workflow, positioning itself primarily as an API design and governance tool with documentation publishing as a secondary capability \[18\]. | Tier | Monthly Billing | Annual Billing | Included Users | Extra Seat (Monthly) | | --- | --- | --- | --- | --- | | Free | $0 | $0 | 1 | N/A | | Basic | $56/mo | $44/mo | 3 | $14/mo | | Startup | $147/mo | $113/mo | 8 | $14/mo | | Pro Team | $453/mo | $362/mo | 15 | $27/mo | | Enterprise | Custom | Custom | Unlimited | Custom | Branding removal is only available on the Pro Team tier at $453 per month on monthly billing \[18\]. SSO is similarly gated to Pro Team. A three-person team on the Basic plan pays $56 per month, but that configuration lacks custom domains, branding control, and SSO \[18\]. Accessing those features requires the Pro Team plan at $453 per month, a more than eight-fold increase. The platform's strength lies in API design governance: style guides, linting rules, and collaborative design review \[18\]. Teams evaluating Stoplight purely as a documentation platform should weigh whether the design-centric feature set justifies the cost. ### Document360 Document360 presents a pricing challenge distinct from every other platform in this analysis: since late 2024, the company has removed all public pricing from its website, requiring prospective customers to request a quote for any of its three tiers \[7\]. | Tier | Public Price | Key Features | | --- | --- | --- | | Professional | Quote required (est. $150+/mo) | Knowledge base, custom domain, API docs, 50+ language translation, Eddy AI agent | | Business | Quote required | Workflow builder, embedded help center, analytics, 30+ integrations, AI search | | Enterprise | Quote required | SSO, decision trees, testing environment, audit trail, priority support | Based on industry reports and third-party review sites, the starting price is estimated at $150 or more per month for the Professional tier \[21\]. The absence of transparent pricing is a meaningful data point. Quote-based pricing typically signals that the vendor prices based on perceived willingness to pay rather than a standardized rate card \[7\]. Document360's architecture is oriented toward knowledge bases rather than the docs-as-code workflow preferred by most engineering teams. Content is managed through a web-based editor rather than through Git repositories and Markdown files \[7\]. ### Archbee Archbee positions itself as a documentation platform that balances accessibility at the entry level with comprehensive features at higher tiers \[20\]. | Tier | Monthly Billing | Annual Billing | Key Features | | --- | --- | --- | --- | | Growing | $100/mo | $80/mo | Unlimited readers, unlimited spaces, custom domain, basic branding, API docs, GitHub integration | | Scaling | $400/mo | $350/mo | Full branding control, review system, reusable content, versioning, localization, advanced access control | | Enterprise | Custom | Custom | All add-ons, multi-team/org, SAML/OIDC SSO, priority support, onboarding | | Add-On | Monthly Price | | --- | --- | | AI Write Assist and AI Q&A | $20/mo \[22\] | | Insights (analytics) | $80/mo \[22\] | The jump from $100 to $400 on monthly billing deserves attention. Features that many teams consider essential (full branding control, content versioning, and localization) are gated behind the Scaling tier, creating a 4x cost increase when a team outgrows the Growing plan \[20\]. The add-on layer adds further cost: AI writing assistance and question answering costs $20 per month, while the Insights analytics dashboard costs $80 per month \[22\]. A team on the Growing plan needing AI and analytics pays $100 plus $20 plus $80 = $200 per month before any per-contributor charges. Archbee offers a startup program providing a 50 percent discount for two years \[20\]. For qualifying startups, the Growing tier drops to $50 per month (monthly billing) and the Scaling tier to $200 per month. ## Real-World Pricing Scenarios Pricing pages tell you what a platform charges. They do not tell you what a team actually pays. This section constructs two scenarios and calculates the actual twelve-month cost for each of the eight platforms using monthly billing rates. Both scenarios assume the team needs a custom domain, AI-powered chat or search, analytics, OpenAPI support, and branding removal. AI usage is estimated at moderate levels: roughly five to seven queries per user per business day. ### Scenario A: Small Startup, 1 Documentation Site, 3 Editors This scenario represents a typical early-stage team: three editors collaborating on a single documentation site. Monthly AI usage is estimated at 500 messages. Jamdesk remains at $29 per month. Three editors fit within the ten-member allocation with no per-seat charges, and there are no AI caps, analytics add-ons, or branding-removal upcharges \[2\]. Total: $29 per month. Mintlify requires the Pro plan at $540 per month (monthly billing): platform analytics live on Pro, and the AI assistant draws on Pro's included 10,000 monthly credits \[14\]. The three editors add nothing, since Mintlify no longer charges per seat. Note that white labeling sits on the Enterprise tier, so full branding removal requires a custom quote on top \[14\]. Total: $540 per month. GitBook requires the Ultimate site plan at $299 per month for branding removal, plus three user plans at $15 each \[15\]\[16\]. Total: $344 per month. ReadMe requires the Pro tier at $300 per month for branding removal (monthly billing), plus the Ask AI add-on ($150/mo) and the Developer Dashboard ($100/mo) \[4\]. Total: $550 per month. Redocly at Enterprise tier (required for AI search): 3 users at $66 each \[17\]. Total: $198 per month. Note: Redocly is focused on API reference rendering and is more limited as a full documentation platform. Stoplight requires Pro Team at $453 per month (monthly billing) for branding removal \[18\]. Total: $453 per month. Document360 requires a sales conversation. Estimated: ~$200 per month \[21\]. Archbee requires the Scaling tier at $400 per month (monthly billing) for branding control, plus the AI add-on ($20/mo) and Insights add-on ($80/mo) \[20\]\[22\]. Total: $500 per month. #### Scenario A: 12-Month Cost Summary (Monthly Billing) | Platform | Monthly Cost | 12-Month Total | Source | | --- | --- | --- | --- | | Jamdesk | $29 | $348 | \[2\] | | Redocly (Enterprise) | $198 | $2,376 | \[17\] | | Document360 (est.) | ~$200 | ~$2,400 | \[21\] | | GitBook (Ultimate + 3 users) | $344 | $4,128 | \[15\]\[16\] | | Stoplight (Pro Team) | $453 | $5,436 | \[18\] | | Archbee (Scaling + add-ons) | $500 | $6,000 | \[20\]\[22\] | | Mintlify (Pro) | $540 | $6,480 | \[14\] | | ReadMe (Pro + add-ons) | $550 | $6,600 | \[4\] | ![Stacked bar chart showing annual cost breakdown by component for each platform in Scenario A](https://cms.jamdesk.com/content/images/2026/04/chart-4-cost-breakdown-v2.png) ### Scenario B: Scaling Organization, 5 Documentation Sites, 30 Editors This scenario represents a growing company managing documentation across multiple products: five documentation sites with thirty editors. Monthly AI usage is estimated at 3,000 messages total. SSO is assumed to be required at this organizational scale. Jamdesk can handle five documentation sites on Pro by adding four extra projects at $15 per month each, and thirty editors at no additional cost, since team members are unlimited on every plan: $29 + $60 = $89 per month, or $1,068 per year \[2\]. Organizations that require SSO, SAML, multi-team governance, or a dedicated account manager would move to the Enterprise plan with custom pricing \[2\]. Mintlify requires separate Pro subscriptions per site. Five instances at $540 each = $2,700 per month \[14\]. The thirty editors add nothing, since Mintlify no longer charges per seat \[14\]. AI usage draws on each instance's included 10,000 monthly credits (50,000 total), with overage billed at $0.01 per credit \[14\]. SSO requires Enterprise (additional cost). Total without SSO: $2,700 per month. GitBook requires five Ultimate site plans: 5 times $299 = $1,495 \[15\]. Thirty user plans: 30 times $15 = $450 \[16\]. Total: $1,945 per month. ReadMe requires Enterprise for multi-project support and SSO, starting at $3,000+ per month on annual billing \[4\]. Monthly billing would be higher. Adding Ask AI ($150) and the Developer Dashboard ($100): $3,250+ per month \[4\]. Redocly at Enterprise: 30 users at $66 each = $1,980, plus additional projects at ~$49 each for 4 extra = $196 \[17\]. Total: $2,176 per month. Stoplight Pro Team at $453 (monthly billing) includes fifteen seats \[18\]. Fifteen extra seats at $27 each = $405 \[18\]. Total: $858 per month. Multi-site support is unclear and may require Enterprise. Document360 requires Enterprise for SSO and multi-project. Estimated: ~$500 per month \[21\]. Archbee requires Enterprise for multi-team and SSO \[20\]. Custom pricing. Estimated: ~$700+ per month based on Scaling tier baseline and contributor scaling \[20\]. #### Scenario B: 12-Month Cost Summary (Monthly Billing) | Platform | Monthly Cost | 12-Month Total | Source | Notes | | --- | --- | --- | --- | --- | | Jamdesk (Pro + extras) | $89 | $1,068 | \[2\] | Or Enterprise for SSO/SAML and multi-team governance | | Document360 (est.) | ~$500 | ~$6,000 | \[21\] | Enterprise quote required | | Archbee (est.) | ~$700+ | ~$8,400+ | \[20\] | Enterprise quote required | | Stoplight | $858 | $10,296 | \[18\] | Multi-site support unclear | | GitBook | $1,945 | $23,340 | \[15\]\[16\] | SSO available on higher user tiers | | Redocly | $2,176 | $26,112 | \[17\] | Limited full-docs capability | | Mintlify | $2,700 | $32,400 | \[14\] | SSO requires Enterprise (add'l cost) | | ReadMe | $3,250+ | $39,000+ | \[4\] | Enterprise required for SSO + multi-project | ![Grouped bar chart comparing annual costs between Scenario A and Scenario B for all platforms](https://cms.jamdesk.com/content/images/2026/04/chart-5-cost-escalation-v2.png) The cost spread at the thirty-person, five-site level is dramatic. GitBook at $23,340 per year and ReadMe at $39,000+ per year represent significant annual commitments for documentation infrastructure alone \[15\]\[4\]. ## Common Pricing Patterns to Watch Documentation platform pricing in 2026 follows a familiar SaaS pattern: the advertised price gets you in the door, and the features you need are behind the next door, and the one after that. Understanding these gating patterns is essential for any team conducting a pricing evaluation. AI gating. In 2026, AI-powered chat and search are baseline expectations for documentation \[13\]. Yet most platforms either exclude AI from base plans or impose usage caps. Mintlify meters AI in credits: the $540/mo Pro plan includes 10,000 credits per month, then $0.01 per credit \[14\]. ReadMe reserves the full Ask AI agent for a $150/mo add-on \[4\]. GitBook splits AI across both plan axes: AI search requires a Premium site plan ($79/mo), while AI writing requires a paid user plan ($15/user/mo) \[15\]\[16\]. Analytics gating. You cannot improve documentation you cannot measure. ReadMe's Developer Dashboard is a $100/mo add-on \[4\]. Archbee charges $80/mo for Insights analytics \[22\]. Stoplight does not offer documentation analytics as a standalone capability \[18\]. Branding gating. Removing a vendor's logo costs the vendor nothing to provide, yet frequently requires a tier upgrade of $200 or more per month. GitBook requires the Ultimate site plan at $299/site/mo \[15\]. ReadMe requires Pro at $300/mo \[4\]. Archbee requires Scaling at $400/mo \[20\]. Stoplight requires Pro Team at $453/mo \[18\]. The per-seat surprise. GitBook charges $15 per user per month on top of per-site fees \[15\]\[16\]. Mintlify dropped per-seat pricing in mid-2026, shifting the meter to AI credits instead \[14\]. A team that budgeted $79 per month for GitBook's Premium plan is actually paying $124 per month once three editors are added, and $344 per month once branding removal is factored in. Add-on stacking. ReadMe's free Starter tier transforms into a $550 per month commitment once branding removal, the full Ask AI agent, and developer analytics are stacked on top of Pro ($300 + $150 + $100) \[4\]. Each add-on is individually justified, but the cumulative effect is a monthly cost that bears little resemblance to the Starter tier's headline. Hidden pricing. Document360 removed all public pricing in late 2024 \[7\]. When a vendor will not tell you what the platform costs, the negotiation dynamic shifts in the vendor's favor. Dual-plan confusion. GitBook's requirement for separate Site Plans and User Plans creates confusion that goes beyond upselling \[15\]\[16\]. A buyer who sees "$79 per month" on the pricing page may not realize that the $79 covers only site-level features and that each editor requires a separate $15/mo user plan. The modular add-on pattern. Some platforms use a base plan that appears cost-effective while selling essential capabilities as individual add-ons. Archbee's Growing tier at $100 per month (monthly billing) looks reasonable until a team realizes that AI question answering costs an additional $20 per month and analytics costs another $80 per month \[22\]. A team that budgeted $100 per month for documentation is actually paying $200 per month. The contributor model mismatch. High-growth teams often face what you might call the "Hybrid Team Problem." Engineers prefer docs-as-code workflows (Markdown, Git, CLI) while non-technical contributors from Product, Support, and Marketing need visual editors. Platforms that only support one model force teams to choose between engineering workflow efficiency and cross-functional contribution. Platforms that resolve this through bidirectional Git sync, where engineers work in their IDEs and non-technical staff use a visual interface while both update the same underlying source, deliver the most sustainable collaboration model. GitBook's bidirectional sync and Jamdesk's Git-based workflow both address this, though at different price points \[15\]\[2\]. ![Waterfall chart showing how advertised prices grow into actual monthly costs across 4 platforms](https://cms.jamdesk.com/content/images/2026/03/chart-6-upsell-waterfall.png) ## Buyer's Checklist Selecting a documentation platform is a multi-year commitment with switching costs that increase over time. The following checklist surfaces the questions that pricing pages frequently obscure. 1. Is AI chat included or an add-on, and what are the usage limits? AI-powered search and chat are baseline expectations in 2026 \[13\]. Confirm whether AI is included, whether usage is metered, and what the overage charge is. Metered allocations exhaust quickly at moderate usage: Mintlify's Pro plan includes 10,000 AI credits per month and bills $0.01 per credit beyond that \[14\]. 2. Are analytics included or gated behind a higher tier? Documentation analytics are essential for identifying gaps. If analytics require a tier upgrade or add-on, factor that cost into your baseline. 3. Will you be able to remove vendor branding on your current plan? Many platforms require a $200 to $400 per month tier upgrade solely for branding removal (white-labeling) \[15\]\[4\]\[20\]. The branding-removal tier is your real starting price. 4. What is the per-seat cost, and is there a seat cap? Per-seat pricing will double or triple the base cost as a team grows \[14\]\[16\]. Calculate costs for your current team size and your projected size in twelve months. 5. If you need multiple documentation sites, does pricing multiply per site? Some platforms charge per site in addition to per user \[15\]. Confirm whether a second site requires a second subscription. 6. Is the published price monthly or annual-only? Several platforms display annual billing rates prominently while burying the monthly rate \[18\]\[14\]\[20\]. A platform advertising $44/mo on annual billing actually costs $56/mo on monthly billing, a 27 percent difference. Always compare monthly billing rates for an apples-to-apples evaluation. 7. Are there usage-based charges for API logs, AI messages, or page views? ReadMe charges for API log volume \[4\]. Mintlify charges per AI message beyond the cap \[14\]. These variable costs are the hardest to predict and the most likely to generate surprises. 8. Does the platform support your workflow, Git-based, WYSIWYG, or both? Some platforms are exclusively Git-based. Others provide only a WYSIWYG editor \[2\]\[15\]\[7\]. Evaluate whether your team works within the platform's authoring model. 9. Will you be able to migrate away easily, or is content locked in a proprietary format? Platforms using standard Markdown or MDX files in Git repositories offer the most portability \[19\]. Ask how content is stored and whether you are able to export in a standard format. 10. Does the platform generate llms.txt for AI-agent readability? As AI agents increasingly consume documentation, llms.txt support ensures your docs remain accessible to both human readers and AI tools \[2\]\[4\]\[23\]. 11. Does the platform support Model Context Protocol (MCP)? MCP is an emerging live connection protocol that exposes documentation as a real-time data source for AI tools during active coding sessions. Platforms with MCP support allow developers' AI assistants to query your documentation directly, reducing hallucinations and improving the accuracy of AI-generated code that depends on your API \[2\]\[4\]\[14\]. 12. Does the platform automatically sync with your code repository to prevent Knowledge Drift? When documentation and code diverge, AI assistants produce incorrect answers that users attribute to your product, not to the AI. Platforms that offer bidirectional Git sync or automated codebase monitoring reduce this risk. Ask whether the sync is real-time, whether the sync supports branching workflows, and whether non-technical contributors are able to participate without breaking the sync \[15\]\[2\]. ## What the Data Shows The central finding of this analysis: the gap between a platform's advertised price and what a team actually pays is the defining problem in documentation platform pricing today. A platform that advertises $79 per month costs $344 per month once branding removal and per-seat charges are applied \[15\]\[16\]. A platform with a $300 per month Pro tier reaches $550 per month with necessary add-ons \[4\]. A free platform ships without AI search, analytics, or support, leaving teams to fill those gaps on their own \[19\]. These are not edge cases. They are the standard experience for teams that move beyond the most basic tier. Teams that select a documentation platform based on the free or entry-level tier often face a reckoning six to twelve months later. The documentation is live, users depend on the site, search engines have indexed the content, and internal workflows have been built around the platform. The cost of migrating is measured in engineering hours, disrupted user experience, and lost search equity. Most teams absorb the price increase rather than migrate, which is the dynamic that tiered pricing is designed to create. Flat-rate pricing eliminates this dynamic. When every feature is included at one price, there is no upsell path, no overage surprise, and no budget approval required when the team needs analytics or AI capabilities. Per-seat and per-site models offer predictability in a different form, with costs that scale linearly but at least transparently. Quote-based models offer the least visibility. Documentation in 2026 functions as AI infrastructure, a dataset that determines whether AI assistants accurately represent your product. Interactive API references and automated OpenAPI synchronization allow developers to reach their first successful API call in minutes rather than hours. AI-powered self-service deflects support tickets. And as AI assistants become a primary interface through which developers evaluate and adopt software, structured documentation with llms.txt and MCP support ensures your product is correctly indexed and represented. When evaluating platforms, model costs based on the feature set you will need in twelve months, not the feature set you need today. Calculate per-seat costs at your projected team size. Estimate AI usage based on realistic query volumes. Confirm that branding removal and analytics are included at the tier you plan to purchase. And always compare monthly billing rates, because the annual discount should not obscure the true list price. ![Feature coverage heatmap showing how all 8 documentation platforms deliver on AI chat, analytics, branding removal, llms.txt, MCP support, and cost efficiency](https://cms.jamdesk.com/content/images/2026/04/chart-7-feature-heatmap-v2.png) ## Documentation Feature Comparison Table All documentation tool prices reflect monthly billing rates. Where a feature is gated behind a specific tier, the required tier and monthly billing cost are noted. | Feature | Jamdesk | Mintlify | GitBook | ReadMe | Redocly | Stoplight | Document360 | Archbee | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | AI Chat/Search | Included ($29/mo) \[2\] | Pro ($540/mo), 10k credits/mo then $0.01/credit \[14\] | Premium site ($79/mo) + user plan ($15/user/mo) \[15\]\[16\] | Ask AI Lite on Pro. Full Ask AI = $150/mo add-on \[4\] | Enterprise ($66/user/mo) \[17\] | Not available \[18\] | Eddy AI (quote required) \[7\] | $20/mo add-on \[22\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Built-in Analytics | Included ($29/mo) \[2\] | Pro only ($540/mo) \[14\] | Premium site ($79/mo) \[15\] | $100/mo add-on \[4\] | Enterprise ($66/user/mo) \[17\] | Not available \[18\] | Business tier (quote) \[7\] | $80/mo add-on \[22\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Branding Removal | Included ($29/mo) \[2\] | Enterprise (custom) \[14\] | Ultimate site ($299/site/mo) \[15\] | Pro ($300/mo) \[4\] | Not on Pro \[17\] | Pro Team ($453/mo) \[18\] | Quote required \[7\] | Scaling ($400/mo) \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Custom Domain | Included ($29/mo) \[2\] | All tiers \[14\] | Premium site ($79/site/mo) \[15\] | Starter (free) \[4\] | Pro ($28/user/mo) \[17\] | Startup ($147/mo) \[18\] | Quote required \[7\] | Growing ($100/mo) \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Per-Seat Cost | Unlimited members included \[2\] | None; flat plan pricing \[14\] | $15/user/mo \[16\] | Included per tier \[4\] | $28 to $66/user/mo \[17\] | $14 to $27/seat \[18\] | Quote required \[7\] | Per-contributor \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | OpenAPI Support | Included \[2\] | All tiers \[14\] | Included \[15\] | All tiers \[4\] | Core feature \[17\] | Core feature \[18\] | Included \[7\] | Included \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | llms.txt | Auto-generated \[2\] | Not available \[14\] | Auto-generated (llms.txt + llms-full.txt) \[23\] | Included free \[4\] | Not available \[17\] | Not available \[18\] | Not available \[7\] | Not available \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | MCP Support | Included \[2\] | Included \[14\] | Not available \[15\] | Included free \[4\] | Not available \[17\] | Not available \[18\] | Not available \[7\] | Not available \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | MDX Support | 25+ components \[2\] | Custom components \[14\] | Block editor \[15\] | Pro ($300/mo) \[4\] | Markdown/MDX \[17\] | Stoplight Markdown \[18\] | Rich editor \[7\] | Block editor \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | CLI Tools | Included \[2\] | Included \[14\] | Git Sync \[15\] | rdme CLI \[4\] | Redocly CLI \[17\] | Stoplight CLI \[18\] | Not available \[7\] | Not available \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Local Dev | Supported \[2\] | Supported \[14\] | Not supported \[15\] | Not supported \[4\] | Supported \[17\] | Supported \[18\] | Not supported \[7\] | Not supported \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Git Integration | Git-based \[2\] | GitHub/GitLab \[14\] | Git Sync \[15\] | Pro ($300/mo) \[4\] | Git-native \[17\] | Included \[18\] | Limited \[7\] | GitHub \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | SSO/SAML | Enterprise \[2\] | Enterprise \[14\] | Higher user plan tier \[16\] | Enterprise ($3,000+/mo annual) \[4\] | Enterprise ($66/user/mo) \[17\] | Pro Team ($453/mo) \[18\] | Enterprise (quote) \[7\] | Enterprise \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Multiple Sites | 1 included; $15/mo per extra project \[2\] | Per-instance \[14\] | Per-site ($79 to $299/site) \[15\] | Enterprise ($3,000+/mo annual) \[4\] | ~$49/add'l project \[17\] | Unclear \[18\] | Quote required \[7\] | Enterprise \[20\] | | --- | --- | --- | --- | --- | --- | --- | --- | --- | * * * ## Endnotes \[1\] Scenarios and feature assumptions defined by the authors based on common production documentation requirements. \[2\] [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com), "Pricing," verified March 2026, team-member pricing re-verified July 2026 (unlimited members on every plan). [https://jamdesk.com/pricing](https://www.jamdesk.com/pricing?ref=cms.jamdesk.com) and [https://www.jamdesk.com/compare](https://www.jamdesk.com/compare?ref=cms.jamdesk.com) and [best API documentation tools](https://www.jamdesk.com/blog/best-api-documentation-tools?ref=cms.jamdesk.com). \[3\] Based on Scenario A comparison across all included platforms. \[4\] ReadMe, "Pricing," verified April 2026. [https://readme.com/pricing](https://readme.com/pricing?ref=cms.jamdesk.com). Tiers: Starter (free), Pro $300/mo monthly billing ($250/mo annual), Enterprise $3,000+/mo (annual only). Add-ons: Ask AI $150/mo, Developer Dashboard $100/mo for 5M logs then $10/1M additional. ReadMe simplified its tier structure in early 2026; the older Startup and Business tiers have been consolidated into Pro. \[5\] ReadMe Ask AI add-on pricing, verified April 2026. [https://readme.com/pricing](https://readme.com/pricing?ref=cms.jamdesk.com) \[6\] All pricing data verified from vendor pricing pages between March 10 and 23, 2026, and re-verified in April 2026. \[7\] Document360, "Pricing," verified March 2026. [https://document360.com/pricing](https://document360.com/pricing?ref=cms.jamdesk.com). No public pricing displayed. Quote-based only since November 2024. Tier structure from Capterra ([https://www.capterra.com/p/177031/Document360/](https://www.capterra.com/p/177031/Document360/?ref=cms.jamdesk.com)). \[8\] Methodology note: see Section "Methodology" for full scenario definitions. \[9\] [Docusaurus](https://docusaurus.io/?ref=cms.jamdesk.com) (docusaurus.io) was evaluated but excluded from this comparison. As a free open-source static site generator, it does not include AI-powered search, usage analytics, managed hosting, branding removal, or customer support, and therefore does not meet the minimum feature requirements defined in our methodology. \[10\] Documentation platform market history based on publicly available sources, 2015 to 2023. \[11\] Documentation platform pricing trends, 2018 to 2023. \[12\] Industry analysis of AI integration in developer tools, 2024 to 2025. \[13\] Stack Overflow, "2025 Developer Survey," [https://survey.stackoverflow.co/2025/](https://survey.stackoverflow.co/2025/?ref=cms.jamdesk.com). See also the AI section at [https://survey.stackoverflow.co/2025/ai](https://survey.stackoverflow.co/2025/ai?ref=cms.jamdesk.com). \[14\] Mintlify, "Pricing," verified March 2026. [https://mintlify.com/pricing](https://mintlify.com/pricing?ref=cms.jamdesk.com). Re-verified July 2026 after Mintlify moved to flat-rate Pro pricing with credit-metered AI. Monthly billing: Pro $540/mo. Annual billing: Pro $450/mo. AI credits: 10,000/mo included on Pro, $0.01 per credit overage. See also Ferndesk, "Mintlify Review 2026." [https://ferndesk.com/blog/mintlify-review](https://ferndesk.com/blog/mintlify-review?ref=cms.jamdesk.com) \[15\] GitBook, "Pricing" (Site Plans), verified March 2026. [https://www.gitbook.com/pricing](https://www.gitbook.com/pricing?ref=cms.jamdesk.com). Monthly billing: Premium $79/site/mo, Ultimate $299/site/mo. Annual billing: Premium $65/site/mo, Ultimate $249/site/mo. See also Featurebase, "GitBook Pricing 2026." [https://www.featurebase.app/blog/gitbook-pricing](https://www.featurebase.app/blog/gitbook-pricing?ref=cms.jamdesk.com) \[16\] GitBook, "Plans" (User Plans), verified March 2026. [https://gitbook.com/docs/account-management/plans](https://gitbook.com/docs/account-management/plans?ref=cms.jamdesk.com). Monthly billing: $15/user/mo. Annual billing: $12/user/mo. \[17\] Redocly, "Pricing," verified March 2026. [https://redocly.com/pricing](https://redocly.com/pricing?ref=cms.jamdesk.com). Monthly billing (Realm: All combined): Pro $28/seat/mo, Enterprise $66/seat/mo. Enterprise+ is custom, yearly only. \[18\] Stoplight, "Pricing," verified March 2026. [https://stoplight.io/pricing](https://stoplight.io/pricing?ref=cms.jamdesk.com). Monthly billing: Basic $56/mo (3 users), Startup $147/mo (8 users), Pro Team $453/mo (15 users). Annual billing: Basic $44/mo, Startup $113/mo, Pro Team $362/mo. \[19\] Docusaurus, official documentation: docusaurus.io \[20\] Archbee, "Pricing," verified March 2026. [https://archbee.com/pricing](https://archbee.com/pricing?ref=cms.jamdesk.com). Monthly billing: Growing $100/mo, Scaling $400/mo. Annual billing: Growing $80/mo, Scaling $350/mo. \[21\] Document360 pricing estimates derived from Capterra ([https://www.capterra.com/p/177031/Document360/](https://www.capterra.com/p/177031/Document360/?ref=cms.jamdesk.com)), G2 ([https://www.g2.com/products/document360/pricing](https://www.g2.com/products/document360/pricing?ref=cms.jamdesk.com)), and Docsie comparative analysis ([https://www.docsie.io/blog/articles/archbee-vs-document360-pricing-comparison-2026/](https://www.docsie.io/blog/articles/archbee-vs-document360-pricing-comparison-2026/?ref=cms.jamdesk.com)). \[22\] Archbee add-on pricing (AI Write Assist $20/mo, Insights analytics $80/mo) from Featurebase, "Archbee Pricing 2026: Is It Worth It?" [https://www.featurebase.app/blog/archbee-pricing](https://www.featurebase.app/blog/archbee-pricing?ref=cms.jamdesk.com). Verified March 2026. \[23\] GitBook, "LLM-ready docs," [https://gitbook.com/docs/publishing-documentation/llm-ready-docs](https://gitbook.com/docs/publishing-documentation/llm-ready-docs?ref=cms.jamdesk.com). Auto-generates llms.txt and llms-full.txt for all published sites. Announced January 2025: [https://docs.gitbook.com/changelog/january-2025/28-january-llms.txt-support-improved-sitemapping-and-more](https://docs.gitbook.com/changelog/january-2025/28-january-llms.txt-support-improved-sitemapping-and-more?ref=cms.jamdesk.com). * * * All prices in this report reflect monthly billing rates unless otherwise noted. Pricing data verified between March 10 and March 23, 2026. Vendor pricing is subject to change. For the most current pricing, visit each vendor's pricing page directly. This analysis was produced by Jamdesk. --- ## Introducing the Jamdesk Podcast URL: https://www.jamdesk.com/blog/introducing-the-jamdesk-podcast Published: 2026-04-17 *We launched the Jamdesk Podcast this week. Boris and Geoff, the co-founders of Jamdesk, host the show. The first episode runs under eight minutes and covers how Jamdesk works, who we built the product for, and what shipped recently. Why We Started a Podcast Developer tools move fast. New features ship, pricing changes, and best practices shift. A podcast gives you a direct line to what we're building and why, without wading through release notes or marketing pages. We wanted a format where y* We launched the Jamdesk Podcast this week. Boris and Geoff, the co-founders of Jamdesk, host the show. The first episode runs under eight minutes and covers how Jamdesk works, who we built the product for, and what shipped recently. ## Why We Started a Podcast Developer tools move fast. New features ship, pricing changes, and best practices shift. A podcast gives you a direct line to what we're building and why, without wading through release notes or marketing pages. We wanted a format where you hear from the people making product decisions. We will generally target about a 5 minute episode, so you can briefly listen on your commute or while you code, you stay current on the work. ## Listen to Episode One Head to [jamdesk.transistor.fm](https://jamdesk.transistor.fm/episodes/the-jamdesk-podcast-april-2026?ref=cms.jamdesk.com) to hear the full episode or search in your favorite podcast app. --- ## JavaScript Promise.all() and Promise.allSettled() in Practice URL: https://www.jamdesk.com/blog/javascript-promise-all Published: 2026-04-07 *Stop awaiting async calls one after another. Promise.all() runs them concurrently, finishing in the time of the slowest call. Real-world examples, error handling, and when to use allSettled instead.* If you're `await`\-ing async calls one after another instead of using `Promise.all()`, you're probably wasting time. Literally. Say you need to hit three APIs and each takes 300ms. Await them sequentially and you're looking at approximately 900ms. Run them with `Promise.all()` and you're done in 300ms, which is the time of the slowest call.\* \*Mostly, since heavy CPU bound processes, such as image processing, can hold up the event loop and make the time cumulative. More on this later. > **Key Takeaways** > > * `Promise.all()` runs independent async operations concurrently, finishing in the time of the slowest call, not the sum of all calls > * If any promise rejects, the entire `Promise.all()` rejects. Use `Promise.allSettled()` when you need partial results > * JavaScript isn't truly parallel. It's async, non-blocking I/O. CPU-bound work won't benefit `Promise.all()` takes an array of promises and returns a single promise that resolves when all of them resolve. You get back an array of `Promises`, which will resolve to (with `await`) an array of results, in the same order you passed them in. From the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all?ref=cms.jamdesk.com): it "takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results." ## How Does Promise.all() Work? ```javascript const urls = [ "https://api.example.com/users", "https://api.example.com/posts", "https://api.example.com/comments", ]; const results = await Promise.all(urls.map((url) => fetch(url))); console.log(results); // [Response, Response, Response] ``` Map over your data, return promises, and `Promise.all()` collects the results. Think of loading a [documentation site](https://jamdesk.com/docs/introduction?ref=cms.jamdesk.com) where you need the page content, sidebar nav, and search index before anything renders. The key point is that the promises start executing the moment you create them. `Promise.all()` isn't launching them. It's just waiting for all of them to finish. ![Sequential await vs Promise.all() timing diagram showing 3 API calls taking 900ms sequentially but only 300ms in parallel](https://cms.jamdesk.com/content/images/2026/04/promise-all-timing-1.webp) ## Real-World: Posting to Multiple Social Networks At my previous company, I built a social media scheduling API. The user writes a post and expects it to go out on X, Facebook, Instagram, and LinkedIn at the same time. Each network has its own auth flow, rate limits, and API quirks, but the user doesn't care about any of that. They want to hit "post" and get results back fast. Assuming the four networks average 200-400ms each, `Promise.all()` cuts our p95 response time from over a second to under 400ms. ```javascript const postToNetworks = NETWORKS.map((network) => { return platforms.includes(network.type) ? network.post(auth[network.type], content, mediaUrls, id) : Promise.resolve(null); }); const results = await Promise.all(postToNetworks); ``` Each network fires off independently. The user gets a consolidated response as soon as the slowest network responds. Without `Promise.all()`, you'd be posting to X, waiting, then Facebook, waiting, then Instagram. Multiply that by thousands of concurrent users and sequential execution isn't just slow, it's a big scaling problem. ## What Happens When One Promise Fails? If _any_ promise rejects, the entire `Promise.all()` rejects and returns the first error. You don't get partial results. This is fine when you want fail-fast behavior. Say you're fetching data that's all required before you can render a page. If one call fails, there's nothing useful to show anyway. ```javascript try { const [users, posts, comments] = await Promise.all([ fetchUsers(), fetchPosts(), fetchComments(), ]); } catch (err) { // One failed — you won't know which without inspecting the error console.error("Something failed:", err.message); } ``` But what if you're posting to social networks and don't want a Facebook failure to kill your Instagram post? Enter `Promise.allSettled()`. ## When Should You Use Promise.allSettled()? `Promise.allSettled()` waits for every promise to either resolve or reject, then gives you the status of each one. No short-circuiting. ```javascript const results = await Promise.allSettled([ postToTwitter(content), postToFacebook(content), postToInstagram(content), ]); // results: // [ // { status: "fulfilled", value: { id: "tweet_123" } }, // { status: "rejected", reason: Error("Rate limited") }, // { status: "fulfilled", value: { id: "ig_456" } }, // ] ``` Now you can handle each result individually. Retry the failures, log the errors, and still return the successful posts to the user. The [State of JavaScript 2024 survey](https://2024.stateofjs.com/en-US/features/?ref=cms.jamdesk.com#promise-static-methods) found that 47% of developers now use `Promise.allSettled()`, up significantly from prior years. It's no longer a niche API. One caveat: You need to be sure to handle the errors of each `Promise` passed to `Promise.allSettled` or you might end up with no return and the system hanging. A good way to prevent this is with the [`AbortController.timeout()` function](https://www.jamdesk.com/blog/abortcontroller-javascript-guide?ref=cms.jamdesk.com). **Rule of thumb:** Use `Promise.all()` when all results are required. Use `Promise.allSettled()` when partial success is acceptable. ## It's Not Actually Parallel A typical interview question is: "Does JavaScript run in parallel." Answer: "No, JavaScript doesn't run promises in parallel. It's single-threaded." You got the job! What's actually happening is asynchronous, non-blocking execution. The [event loop](https://www.geeksforgeeks.org/javascript/what-is-an-event-loop-in-javascript/?ref=cms.jamdesk.com) kicks off all the I/O operations (API calls, file reads, database queries) and moves on. When each one completes, its callback lands back on the event loop. The practical effect _feels_ parallel because the I/O operations happen outside the JS thread. But if your "async" work is CPU-bound (parsing a massive JSON blob, image processing as mentioned above), `Promise.all()` won't help. You'll just be running those tasks sequentially on the same thread. For CPU-bound work, look at [Worker threads](https://nodejs.org/api/worker_threads.html?ref=cms.jamdesk.com) in Node.js or Web Workers in the browser. One other thing: don't use `Promise.all()` when your calls depend on each other. If call B needs the result of call A, they can't run concurrently. Only reach for it when the operations are genuinely independent. ## Quick Reference: All Four Promise Methods Which method do you actually need? Here is a chart with a few extras such as `race` and `any`. | Method | Resolves when | Rejects when | Best for | | --- | --- | --- | --- | | `Promise.all()` | All fulfill | Any rejects | Fetching required data in parallel | | `Promise.allSettled()` | All settle | Never | Partial success is fine (social posts, batch ops) | | `Promise.race()` | First settles | First settles | Timeouts with `AbortSignal.timeout()` | | `Promise.any()` | First fulfills | All reject | Fallback chains, redundant sources | `Promise.race()` settles with whichever promise finishes first. The classic use case is timeouts. Pair it with `AbortController` (as mentioned above) to cancel the request cleanly instead of leaving it hanging. `Promise.any()` ignores individual rejections and gives you the first success, which is perfect for hitting multiple CDN endpoints and taking whichever responds first. Resolving Promised Sequentially If you're looking to [resolve promises sequentially](https://www.jamdesk.com/blog/resolve-promises-sequentially-javascript?ref=cms.jamdesk.com), review our guide How to Resolve Promises Sequentially in JavaScript to see how. --- ## AbortController Beyond Fetch: Timeouts, Cleanup, and Signal Composition URL: https://www.jamdesk.com/blog/abortcontroller-javascript-guide Published: 2026-04-04 *As a Node.js developer, you probably know AbortController as the built-in API that cancels fetch(). If you're not familiar with it, AbortController is an API interface that allows you to cancel web request. I've always seen it as a peculiarity, and honestly detriment, of fetch() not natively supporting cancel or other advanced features like axios. Why do I need to instantiate another class to pass to fetch()? However, over time I learned AbortController does a lot more than just cancel. AbortCo* As a Node.js developer, you probably know `AbortController` as the built-in API that cancels `fetch()`. If you're not familiar with it, `AbortController` is [an API interface](https://developer.mozilla.org/en-US/docs/Web/API/AbortController?ref=cms.jamdesk.com) that allows you to cancel web request. I've always seen it as a peculiarity, and honestly detriment, of `fetch()` not natively supporting cancel or other advanced features like `axios`. Why do I need to instantiate another class to pass to `fetch()`? However, over time I learned `AbortController` does a lot more than just cancel. `AbortController` is a general-purpose JavaScript cancellation primitive that works with timeouts, event listeners, streams, concurrent operations, and graceful shutdowns. It's been in every browser with JavaScript ([97% support](https://caniuse.com/abortcontroller?ref=cms.jamdesk.com)) and Node.js since v15. Let's go over how you can use it beyond cancel. > **Key Takeaways** > > `AbortSignal.timeout()` replaces manual `setTimeout`/`clearTimeout` pairs with a single line > > The `signal` option on `addEventListener` auto-removes listeners on abort, eliminating a [common source of memory leaks](https://stackinsight.dev/blog/memory-leak-empirical-study/?ref=cms.jamdesk.com) > > `AbortSignal.any()` composes multiple cancellation conditions (user action, timeout, navigation) into one signal ## Cancelling Fetch You might already know this part. Create a controller, pass its `signal` to `fetch()`, call `abort()`. `signal` is a universal cancellation token, meaning any API that accepts `signal` can be cancelled this same way - including `fetch` and `axios`. ([MDN reference](https://developer.mozilla.org/en-US/docs/Web/API/AbortController?ref=cms.jamdesk.com)) A common real-world example is search-as-you-type. Every keystroke fires a new request, but you only care about the latest one. Without cancellation, stale responses can arrive out of order and overwrite newer results: ```javascript let currentController = null; searchInput.addEventListener('input', async (e) => { // Cancel the previous search if still in flight currentController?.abort(); currentController = new AbortController(); try { const res = await fetch(`/api/search?q=${e.target.value}`, { signal: currentController.signal }); renderResults(await res.json()); } catch (err) { if (err.name !== 'AbortError') throw err; } }); ``` The above code prevents race conditions and debounce, though you might still debounce to reduce server load. ## AbortSignal.timeout() Say you're building an API endpoint in Node.js that calls a third-party service. If that service hangs, your endpoint hangs too or just takes too long — and your user stares at a spinner, you have an unhappy or departing user. So you add a timeout: ```javascript const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); try { const res = await fetch('/api/slow', { signal: controller.signal }); clearTimeout(timeoutId); return await res.json(); } catch (err) { clearTimeout(timeoutId); throw err; } ``` In my previous company, I wrote a common fetch utility function that wrapped `fetch` with the timeout as a param. It worked well, but still it always felt yucky because I had to import the function in every file that needed fetch. And if you forget the second `clearTimeout` call (not that I ever did that!) you have a leaked a timer. `AbortSignal.timeout()` replaces all of it: ```javascript const res = await fetch('/api/slow', { signal: AbortSignal.timeout(5000) }); ``` Boom! No manual timer. No cleanup. No forgotten `clearTimeout` in an error path. The runtime handles everything. The code is shorter and the failure mode is obvious. This works with anything that accepts a signal. Node.js built-ins like `fs.readFile`, `timers/promises`, and `fetch` all support it natively. I switched to `AbortSignal.timeout()` in our common fetch util function, but starting over again I wouldn't even have created the common function. ## Event Listener Cleanup This is the most underused feature. Since 2021, `addEventListener` takes a `signal` option. When the signal aborts, the listener is removed automatically. ```javascript const controller = new AbortController(); element.addEventListener('click', handleClick, { signal: controller.signal }); element.addEventListener('keydown', handleKey, { signal: controller.signal }); element.addEventListener('scroll', handleScroll, { signal: controller.signal }); // Remove ALL three with one call controller.abort(); ``` As with the `AbortSignal`, we get to simplify the code a lot with no `removeEventListener`, no keeping references to handler functions and no forgetting to clean one up. This matters — a [study of 500 repositories](https://stackinsight.dev/blog/memory-leak-empirical-study/?ref=cms.jamdesk.com) found that 86% had at least one missing cleanup pattern. Event listener removal issues accounted for 19% of all leak patterns (StackInsight, 2026). ### In React If you use React, this makes your `useEffect` particularly clean. For example, if you have a dashboard component that needs to listen for window resizes, watch network status, and fetch initial data, all of which need cleanup when the component unmounts: ```javascript useEffect(() => { const controller = new AbortController(); window.addEventListener('resize', handleResize, { signal: controller.signal }); window.addEventListener('online', handleOnline, { signal: controller.signal }); fetchUserData({ signal: controller.signal }); return () => controller.abort(); }, []); ``` One controller cleans up every listener and cancels every fetch when the component unmounts. You no longer have to worry about removing that one listener that causes a slow memory leak in production. If you're building with [Next.js and React](https://www.jamdesk.com/blog/build-a-tiny-docs-site-with-next-js-in-under-an-hour?ref=cms.jamdesk.com), this pattern keeps components leak-free across route transitions. ## AbortSignal.any() Sometimes an operation should cancel for more than one reason. A file upload, for example, should stop if the user clicks cancel, if the page navigates away, or if 60 seconds elapse. `AbortSignal.any()` composes multiple conditions into one signal: ```javascript function fetchWithTimeoutAndCancel(url, userController) { const signal = AbortSignal.any([ userController.signal, AbortSignal.timeout(5000) ]); return fetch(url, { signal }); } ``` Here's the full file upload example: ```javascript const pageController = new AbortController(); const userController = new AbortController(); window.addEventListener('beforeunload', () => pageController.abort()); cancelButton.addEventListener('click', () => userController.abort()); const signal = AbortSignal.any([ pageController.signal, userController.signal, AbortSignal.timeout(60000) ]); await uploadFile(file, { signal }); ``` This prevent you having to deal with manual coordination between timers and event handlers. The composed signal fires the moment any condition is met. ## Cancelling Promise.all() Now let's expand the dashboard example to load data from five microservices in parallel. If one service is down, `Promise.all()` rejects — but the other four requests keep running, consuming bandwidth and server resources for results nobody will see. Share a controller across all requests to cancel the ones hanging around: ```javascript async function fetchAllOrNothing(urls) { const controller = new AbortController(); try { return await Promise.all( urls.map(url => fetch(url, { signal: controller.signal })) ); } catch (err) { controller.abort(); // Cancel the rest throw err; } } // Dashboard loading five widgets in parallel const data = await fetchAllOrNothing([ '/api/revenue', '/api/users', '/api/orders', '/api/inventory', '/api/notifications' ]); ``` When any fetch fails, `controller.abort()` cancels every remaining request immediately. This can be especially useful when your [API endpoints](https://www.jamdesk.com/blog/what-is-an-api?ref=cms.jamdesk.com) fan out to multiple backends. ## Graceful Shutdown in Node.js When a Node.js server receives `SIGTERM` (during a deploy, a container restart, or a scale-down), in-flight requests need to finish or cancel cleanly. Without that, you get orphaned database connections, half-written responses, and process crashes from unhandled promise rejections (the default since Node.js 15). A shared shutdown controller (using the `AbortController` interface) can help with this: ```javascript const shutdownController = new AbortController(); process.on('SIGTERM', () => { console.log('Shutting down...'); shutdownController.abort(); }); app.get('/api/data', async (req, res) => { try { const data = await fetch('https://upstream-service/data', { signal: shutdownController.signal }).then(r => r.json()); res.json(data); } catch (err) { if (err.name === 'AbortError') { res.status(503).json({ error: 'Server shutting down' }); } } }); ``` ### Per-Request Cancellation You can also cancel work when a specific client disconnects. If someone triggers an expensive report and then refreshes the page, there's no point finishing it: ```javascript app.get('/api/report', async (req, res) => { const controller = new AbortController(); req.on('close', () => controller.abort()); try { const report = await generateExpensiveReport({ signal: controller.signal }); res.json(report); } catch (err) { if (err.name !== 'AbortError') throw err; } }); ``` The report generation stops immediately instead of running to completion and sending a response to nobody. ## Making Your Functions Support AbortController Similar to my common utility function, you can write your own that accept a `signal` parameter and check it at safe points: between async operations, between loop iterations, or before expensive work. ```javascript async function processQueue(items, { signal } = {}) { signal?.throwIfAborted(); // Bail early if already cancelled const results = []; for (const item of items) { signal?.throwIfAborted(); // Check between iterations results.push(await processItem(item)); } return results; } ``` This is the same pattern [Node.js core](https://nodejs.org/api/globals.html?ref=cms.jamdesk.com#class-abortcontroller) uses for `fs.readFile`, `timers/promises`, and other built-in APIs. Your callers get cancellation for free. ## Quick Reference **JavaScript Core API** — available in all browsers and Node.js 15+: * `new AbortController()` — creates a controller with a `.signal` property * `controller.abort(reason)` — triggers the signal; optional `reason` becomes `signal.reason` * `controller.signal.aborted` — boolean, `true` after `abort()` is called **Static helpers** — newer, but widely supported: * `AbortSignal.timeout(ms)` — returns a signal that auto-aborts after N milliseconds (Node 17.3+, [96% browsers](https://caniuse.com/mdn-api_abortsignal_timeout_static?ref=cms.jamdesk.com)) * `AbortSignal.any(signals)` — returns a signal that aborts when any input signal aborts (Node 20+, [90% browsers](https://caniuse.com/mdn-api_abortsignal_any_static?ref=cms.jamdesk.com)) **Instance methods** on `AbortSignal`: * `signal.throwIfAborted()` — throws `signal.reason` if already aborted, otherwise does nothing (Node 17.3+) * `signal.addEventListener('abort', fn)` — listen for the abort event directly ## Some Final Gotchas Here are few things that have tripped me up in the past...lessons learned, as you might say. ### Only use an AbortController instance once Once you call `abort()`, the signal's `.aborted` property is permanently `true` and cannot be reset. Every listener attached to it has already been notified and cleaned up. This is intentional by the API designers since it prevents bugs where you accidentally reuse a stale signal and either cancel something you didn't mean to, or miss a cancellation because the signal already fired. In general, only use one controller per operation or lifecycle. In a React effect, that means a new controller on every mount. In an Express route, a new controller per request. They're cheap to create to don't be afraid to use them (see below). ### AboutController isn't expensive An `AbortController` is just an `EventTarget` with a single `abort` event and a boolean flag. There's no background timer, no thread, no I/O. Creating one is comparable to creating a plain object — V8 allocates it on the heap and that's it. The only cost that could add up is attaching many listeners to a single signal, since each listener is stored in an array on the `EventTarget`. In practical terms, even dozens of listeners per signal has no measurable impact. If you're creating thousands of controllers in a tight loop (say, one per item in a batch), you might want to share a single controller across the batch instead — which is exactly the `Promise.all()` pattern above. ### Catch AbortErrors Every API that accepts a signal throws the same error type when cancelled: an `AbortError`. You can catch it alongside other errors and branch: ```javascript try { const res = await fetch('/api/data', { signal }); return await res.json(); } catch (err) { if (err.name === 'AbortError') { // User cancelled, page navigated away, or timeout hit. // Usually you just do nothing here. return null; } // Actual network error, server error, etc. throw err; } ``` If you passed a custom reason to `abort('user cancelled')`, it's available on `err` directly (the reason becomes the thrown value). With `AbortSignal.timeout()`, the thrown error is a `TimeoutError` instead of `AbortError`, so you can distinguish timeouts from manual cancellations if you need to: ```javascript } catch (err) { if (err.name === 'TimeoutError') { showMessage('Request timed out. Try again?'); } else if (err.name === 'AbortError') { // Intentional cancellation — do nothing } else { throw err; } } ``` --- ## Why Google PageSpeed Actually Matters and What You Can Ignore URL: https://www.jamdesk.com/blog/why-google-pagespeed-matters Published: 2026-03-16 *PageSpeed Insights gives you four scores and dozens of metrics. Most of them don't matter. Here's what does, for both Google and the AI crawlers that are quickly becoming just as important.* We ran Google PageSpeed Insights (Lighthouse score) on our own [docs site](https://jamdesk.com/docs?ref=cms.jamdesk.com). Mobile: 95. Desktop: 98. We spent a lot of time making sure our software documentation tool generated super high score for our customer. It wasn't easy and took many iterations (thank you Claude Code for the assist). But was it worth it? These measurements encompass a lot of scores, so understanding what they mean is the first step toward knowing which numbers to care about and which to ignore. The URL we tested: [jamdesk.com/docs/introduction](https://pagespeed.web.dev/analysis/https-jamdesk-com-docs-introduction/lu2gb3ozch?form_factor=desktop&ref=cms.jamdesk.com). You can run the same test on your own site at [pagespeed.web.dev](https://pagespeed.web.dev/?ref=cms.jamdesk.com) right now. We'll walk through what we found, what we decided to fix, and what we decided wasn't worth the engineering time. ![Jamdesk PageSpeed Result on Mobile](https://cms.jamdesk.com/content/images/2026/03/pagespeed-mobile.webp) Jamdesk PageSpeed Result on Mobile ![Jamdesk PageSpeed Result on Desktop](https://cms.jamdesk.com/content/images/2026/03/pagespeed-desktop.webp) Jamdesk PageSpeed Result on Desktop ## What Google PageSpeed Insights Actually Measures PageSpeed gives you four scores: Performance, Accessibility, Best Practices, and SEO. Each one is a 0-100 number with a color code, like a report card. Green (90-100) means good and you rock. Orange (50-89) means needs improvement and need to work on it. Red (0-49) means poor and you suck. ### Performace Most people fixate on Performance. Fair enough, and so do we. That's the one everyone screenshots (um, see above), the one that shows up in debates about whether Lighthouse is even useful, the one your manager asks about in stand-ups when someone reads a blog post about Core Web Vitals. It's also the only score that's a weighted average of five underlying metrics rather than a simple checklist. The weights matter because they tell you where to spend your time: * **TBT (Total Blocking Time):** 30% of your score * **LCP (Largest Contentful Paint):** 25% * **CLS (Cumulative Layout Shift):** 25% * **FCP (First Contentful Paint):** 10% * **Speed Index:** 10% TBT, LCP, and CLS account for 80% of the Performance number. FCP and Speed Index split the remaining 20%. If you're trying to improve your score, ignore FCP and Speed Index until the big three are green. ### SEO The SEO score is misleading. Our 100 doesn't mean we'll [rank #1 for anything](https://x.com/colinhacks/status/1883650393303114031?s=20&ref=cms.jamdesk.com). It means Google can crawl us. The score checks for meta tags, viewport settings, crawlable links, and indexability. Passing means "we won't actively block search engines from finding you." That's a low bar. The real SEO game happens elsewhere. ### Best Practices & Accessibility Best Practices and Accessibility are genuinely useful audits for code quality and user experience. They don't affect search ranking directly. Fix the issues they flag because they matter to your users, not because Google told you to. And please don't ignore accessibility. It is important for your user both with and without disabilities. ### Real-World vs Lab One thing that trips people up: the difference between lab data and real-world field data. PageSpeed shows lab data by default. That's a simulated test run in a controlled environment. Field data comes from the Chrome User Experience Report, aggregated from real Chrome users who visit your site. Our report shows "No Data" for field data because the page doesn't have enough real-world traffic in Chrome's dataset. Many developer documentation sites will see the same thing. It doesn't indicate a problem. The Diagnostics and Opportunities sections below the scores deserve a mention too. Those red and orange triangles ("Render blocking requests," "Reduce unused JavaScript") are suggestions, not failures. They don't directly affect your score. Developers often panic about these. Don't. Treat them as a prioritized to-do list. Pick the ones with the biggest estimated savings and ignore the rest until they actually cause problems. Think of the Performance score like a blood test. The individual metrics tell you what's wrong. The overall number is just a summary. ## What Actually Matters (And What Doesn't) Google uses three metrics as official ranking signals. They call them Core Web Vitals. _Everything else in the report is diagnostic._ **LCP measures when your main content appears.** Under 2.5 seconds is good. Between 2.5 and 4 seconds needs improvement. Over 4 seconds is poor. Our mobile LCP is 2.1 seconds, which puts us in the "good" range, but when we first started it was in the red. Desktop is 0.6 seconds, which is a significant difference. Note: Never panic about mobile because Lighthouse simulates a mid-range phone on throttled 4G and it will almost always be lower, sometimes significantly, than desktop. The desktop number proves our server and content delivery are fast. The mobile gap comes from the network simulation, and 2.1s or even 3s on simulated slow 4G is totally fine for a documentation site with code blocks and images. **CLS measures visual stability.** Under 0.1 is good. Ours: 1.03 mobile, 0.027 desktop. Both solid. CLS catches the thing users hate most: content jumping around while they're trying to read or click something. Images loading without dimensions, ads injecting themselves, web fonts swapping in and shifting text. If your CLS is much above 0.1, fix it before touching anything else. Users feel layout shifts viscerally, and they don't like it. **INP replaced FID in March 2024 as the third Core Web Vital.** It measures responsiveness: how quickly the page reacts when someone clicks, taps, or types. Under 200 milliseconds is good. TBT is the lab proxy for INP, which is why it carries 30% of the Performance score weight. ![Our mobile metrics. CLS at 1.03s is the only orange value, everything else is green.](https://cms.jamdesk.com/content/images/2026/03/mobile-metrics-2.webp) Our mobile metrics. CLS at 1.03s is the only orange value, everything else is green. Now, what you can safely care less about. The overall score number. The difference between 95 and 98 is functionally meaningless. Both are green. Nobody loads a page and thinks "this felt like a 95, not a 98." If you're above 90, you're good and you can stop optimizing the score and start optimizing the actual user experience. Speed Index and FCP are the two metrics that sound important but carry little weight. Speed Index is synthetic, not a Core Web Vital, and not a Google ranking signal. FCP tells you when the first pixel renders, which helps with debugging, but it isn't a ranking signal independent of LCP. Together they account for only 20% of the Performance score. The mobile vs desktop gap panics people more than it should. Mobile scores are always lower because Lighthouse simulates a Moto G Power on throttled 4G. Our site drops from 98 to 95 across that divide, and that's completely normal. If your mobile Performance score is above 90, you're ahead of most of the web. ## Why PageSpeed Matters for SEO Since 2021, [Core Web Vitals](https://developers.google.com/speed/docs/insights/v5/about?ref=cms.jamdesk.com#field-data-label) have been Google ranking signals. The specific metrics have evolved (INP replaced FID in March 2024), but the principle hasn't changed. Their impact, though, is frequently overstated. Core Web Vitals are a tiebreaker. Content relevance wins first, and always has. Google's own documentation says page experience signals "align with what our core ranking systems seek to reward." Translation: if two pages have equally relevant content for a query, the faster one edges ahead. A slow site won't outrank a fast one on speed alone, and a fast site won't magically rank for irrelevant queries. The real damage from poor performance isn't the ranking signal. It's bounce rate. A page that takes 5 seconds to load on mobile loses visitors before Google's algorithm even enters the picture. Google tracks if people leave and they don't come back. And that behavior signal feeds back into rankings through engagement metrics, creating a compounding problem where slow pages get fewer visitors, generate worse engagement data, and gradually slide further down the results page in a cycle that's difficult to reverse once it starts. Be honest with yourself about this: PageSpeed improvements alone won't transform your rankings. Content quality, backlinks, and domain authority still dominate. But ignoring performance creates a ceiling on how well you can rank, particularly on mobile where most searches happen. In summary, PageSpeed is important until it gets to 90 and above that it becomes a vanity metric. ## Why AI Crawlers Care About Your Speed For twenty years, "optimize for search" meant "optimize for Google." Not anymore. ChatGPT, Claude, Perplexity, Google AI Overviews, and Gemini now answer questions directly, citing sources inline. An [Ahrefs study](https://ahrefs.com/blog/ai-seo-statistics/?ref=cms.jamdesk.com) of 863,000 keywords found that 25% of Google searches now surface AI Overviews. And the sourcing patterns are completely different from traditional search: 80% of URLs cited by ChatGPT and Perplexity don't even appear in Google's top 100 results. AI citation and traditional search ranking have decoupled. Your PageSpeed work now serves two separate audiences that evaluate your site through different mechanisms. AI crawlers like GPTBot, ClaudeBot, and PerplexityBot have timeout budgets between 1 and 5 seconds. Googlebot is patient. It will wait, retry, come back later. AI crawlers won't. If your server takes too long to respond, they move on, and your page doesn't get indexed into the AI's knowledge at all, which means it can never be cited in any AI-generated answer no matter how authoritative or well-written the content is. This is a visibility problem and not a ranking problem. They also don't execute JavaScript. A Vercel and MERJ analysis of 500 million GPTBot requests found [zero evidence of JavaScript execution](https://seo.ai/blog/does-chatgpt-and-ai-crawlers-read-javascript?ref=cms.jamdesk.com). Zero. If your content depends on React hydration to appear in the DOM, AI crawlers see an empty `
` and move on, which means every single-page application that hasn't implemented server-side rendering or have an [llms.txt file](https://jamdesk.com/docs/ai/llms-txt?ref=cms.jamdesk.com#pages) or [viewable as markdown](https://jamdesk.com/docs/ai/markdown-source?ref=cms.jamdesk.com#raw-markdown-source) is completely invisible to AI systems regardless of how good the content is. The speed numbers back this up. SE Ranking analyzed 2.3 million pages across 295,000 domains and found that pages with a First Contentful Paint under 0.4 seconds averaged 6.7 ChatGPT citations. Pages with FCP over 1.13 seconds averaged 2.1. A fraction of a second, a 3x difference in citation frequency. [Cloudflare's bot traffic reports](https://blog.cloudflare.com/from-googlebot-to-gptbot-whos-crawling-your-site-in-2025/?ref=cms.jamdesk.com) show GPTBot requests grew 305% between May 2024 and May 2025. This traffic source is accelerating fast. The mechanisms are different, and that distinction matters. Google uses Core Web Vitals as a ranking signal. It's one factor among hundreds, a tiebreaker. AI crawlers use speed as a gating function. Can I fetch this page within my compute budget? Yes or no. There's no gradual penalty, no "needs improvement" middle ground. Your page loads in time, or it doesn't exist. ## What To Do About It Practical fixes, ordered by impact. **For traditional SEO**, fix LCP first. It's 25% of your Performance score and the metric users actually feel. Optimize images (serve webp, set explicit width and height attributes, lazy-load below the fold). Preload your critical CSS and fonts. Eliminate layout shifts next. CLS is also 25% of the score and the most annoying user experience problem. The usual culprits: images without dimension attributes, dynamic content injecting above the fold, web fonts loading late and swapping. Set dimensions on every image. Use [`font-display: swap`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face/font-display?ref=cms.jamdesk.com) with a fallback that matches the web font's metrics. Don't chase 100. Green is a good goal. The engineering effort required to squeeze from 90 to 100 almost never justifies the near-zero user experience improvement. **For AI discovery**, the priorities are different. Speed is important, so consider server-side rendering. If your content requires client-side JavaScript to appear in the DOM, AI crawlers can't see it. Static generation, SSR, IRS, or having an llms.txt or markdown file available are all good solutions. We wrote a walkthrough of [building a server-rendered docs site with Next.js](https://www.jamdesk.com/blog/build-a-tiny-docs-site-with-next-js-in-under-an-hour?ref=cms.jamdesk.com) if you want to see the approach. Keep TTFB (Time to First Byte) under 200ms. This is the metric AI crawlers feel most. It determines whether they wait for your page or abandon the request. Add [structured data using JSON-LD](https://jamdesk.com/docs/content/seo?ref=cms.jamdesk.com#json-ld-structured-data), such as schema markup, FAQ blocks, author information, and article metadata. Think of structured data as an API for AI systems. The crawler can parse your prose, but structured data tells it exactly what your page is about without ambiguity. Our [API documentation tools comparison](https://www.jamdesk.com/blog/best-api-documentation-tools?ref=cms.jamdesk.com) covers how different tools handle AI-readiness if you want to dig deeper. As mentioned briefly before, an `/llms.txt` file is also useful. It's an emerging standard for LLM-friendly content summaries, but there is some debate on if any AI bot uses it. We serve ours at [jamdesk.com/llms.txt](https://www.jamdesk.com/llms.txt?ref=cms.jamdesk.com). It gives AI crawlers a table of contents for your site's content without requiring them to crawl every page. ## The Score Isn't a Grade PageSpeed isn't a report card, well, it is a report card, but mainly it should be looked at as a diagnostic tool. It is a surprisingly useful one if you look at the individual metrics instead of obsessing over whether your overall number is a 91 or a 97 or a perfect 100 that you screenshot and post on X. The individual metrics tell you what to fix. In 2026, the audience for your site's performance isn't just Google anymore. Every AI assistant deciding whether to cite your content is running the same calculation: is this page fast enough to be worth fetching? The answer should be yes. --- ## How to Blur Sensitive Text in Screenshots with AI + ImageMagick URL: https://www.jamdesk.com/blog/blur-screenshots-with-ai Published: 2026-03-06 *Stop manually blurring screenshots. Use AI to detect sensitive text and ImageMagick to redact it in one command.* Last month I dropped a screenshot into a GitHub issue. Standard stuff, terminal output from a failing deploy. That screenshot sat there for six hours before someone noticed the Stripe live key in the corner. And the customer email three lines above it. And the database connection string at the top of the `.env` dump. Six hours on a public repo. Ok, I made up that example to illustrate what we've all done at some point - forgetting to blur out sensitive info. When this happens, you need to revoke the key, rotate credentials, and you're basically in fire drill for the rest of the day. And it is easy for this to happen. Developers paste screenshots constantly: PRs, Slack threads, documentation, blog posts, support tickets. Most of the time the sensitive data isn't the point of the screenshot. It's background noise you don't notice until someone points it out. Documentation screenshots is common for me. I grab a screenshot of my API dashboard to show a feature, and the dev tools panel is open in the background with an Authorization header visible. My standard blurring workflow is to open up Xnapper and then manually blur out and image...or if I'm lazy ask a co-worker who is skilled with Photoshop to do it for me. However, now with AI agents, it has become easy. An AI agent reads the screenshot (or takes one for you), finds the sensitive text, and uses the command line tool ImageMagick to blur and redact the sensitive text. I even created a blur skill to help. That's what we'll be walking through shortly. **The short version:** Install the [blur-image skill](https://github.com/jamdesk/skills?ref=cms.jamdesk.com), tell your AI assistant "blur the sensitive data in screenshot.png," and it handles everything — detects credentials, emails, and tokens, asks what you want blurred, and runs [ImageMagick](https://imagemagick.org/?ref=cms.jamdesk.com). You never touch a pixel coordinate. ## The Way The latest AI models are surprisingly good at finding text in screenshots, like Opus 4.6 or Codex 5.3. They can read terminal output, identify email-shaped strings, recognize API key patterns, and distinguish between sensitive content (a `sk_live_` key) and harmless content (a syntax-highlighted keyword). They do what your eyes skip: scan every pixel of an image for anything that looks like it shouldn't be shared. Feed a screenshot to Claude Code or Codex and ask "what sensitive text is in this image?" and you'll get back a list with coordinates. Accurate enough to be useful, imprecise enough that you need padding. ImageMagick is my favorite and handles the actual redaction. It's a command-line image processing tool that's been around since 1990. You point it at a rectangular region in an image and tell it to blur, and the pixels in that region become unreadable. Combine the AI's ability to find sensitive regions with ImageMagick's ability to blur them, and you get a workflow that catches things you'd miss and executes in a few minutes. No GUI, no dragging rectangles, no "did I cover that whole token or just most of it." Don't you just love AI! ## Prerequisites * **ImageMagick 7+**: `brew install imagemagick` on macOS, `apt install imagemagick` on Ubuntu * **An AI coding assistant**: Claude Code, Codex, Cursor, Windsurf, or any tool that can read images * **The blur-image skill** (recommended): `npx skills add jamdesk/skills --skill blur-image` This [Vercel skills package](https://www.npmjs.com/package/skills?ref=cms.jamdesk.com) is a great way to install and manage skills. Once installed just run with /blur-image. * A screenshot you want to redact ## The Core Command ImageMagick's `-region` flag is the key to targeted blurring. It selects a rectangular area of the image, applies the next operation only to that area, then resets. Stack multiple `-region` flags to blur several areas in one pass: ```bash magick input.png -region 200x50+350+120 -blur 0x20 output.webp ``` The syntax breaks down like this: `-region WxH+X+Y` selects a rectangle W pixels wide and H pixels tall, starting at X pixels from the left edge and Y pixels from the top. ImageMagick uses a top-left origin, so `+0+0` is the upper-left corner. `-blur 0x20` applies a Gaussian blur with sigma 20 to the selected region. After the blur, the region resets and the next operation applies to the full image (or you can chain another `-region` for a different area). ![Terminal screenshot showing fake credentials including database URLs, API keys, and personal data in plain text](https://cms.jamdesk.com/content/images/2026/03/before-terminal.webp) A terminal session with fake credentials: a .env dump, a curl command with a GitHub token, and API response data. ![The same terminal screenshot with sensitive regions blurred using ImageMagick, showing redacted credentials while keeping variable names readable](https://cms.jamdesk.com/content/images/2026/03/after-terminal-v3.webp) One command, per-line blur regions. Variable names stay readable; actual values are gone. The environment variable names stay readable so you can tell what was redacted, but the actual secret values are gone. We used separate `-region` flags for each value, one per `.env` line, one for the Bearer token, and one per JSON field. The blur starts right after the `=` or `:` delimiter, so `JWT_SECRET=` is fully visible while the value after it is smeared. For JSON values, the blur covers the surrounding quotes too, so you don't get stray `"` characters sitting at the edges of a blur region looking weird. ### Blur Strength Matters Sigma in `-blur 0xSIGMA` controls how aggressively the pixels are scrambled. This isn't cosmetic. It's a security parameter. [Research has shown](https://arxiv.org/html/2506.12344v1?ref=cms.jamdesk.com) that Gaussian blur with a low sigma can be partially reversed using deblurring algorithms, especially on high-contrast text against a solid background (exactly what terminal screenshots look like). Use sigma 15 or higher for anything with real credentials. We default to 20. For maximum security, skip blur entirely and use solid fill: ```bash magick input.png -region 200x50+350+120 -fill black -colorize 100 output.webp ``` Solid fill is irreversible. Original pixels are replaced, not smeared. Tradeoff is aesthetics: black rectangles look more aggressive than a soft blur. ### Multiple Regions Real screenshots usually have several sensitive areas. Chain them: ```bash magick screenshot.png \ -region 560x30+170+62 -blur 0x20 \ -region 470x35+250+173 -blur 0x20 \ -region 250x80+65+235 -blur 0x20 \ -quality 85 screenshot-blurred.webp ``` All regions are processed in a single pass. ImageMagick reads the image once, applies each region+blur pair, and writes the output. ## Detecting Sensitive Text with Claude Code With the blur-image skill installed, you don't think about coordinates at all. Give Claude Code, the tool of your choice, a screenshot and describe what you want in plain English: ```bash $ claude > blur the sensitive data in screenshot.png using /blur-image skill I'm using the blur-image skill to identify and blur sensitive regions. Preflight: magick found at /opt/homebrew/bin/magick (v7.1.2) Image: screenshot.png (820x404 PNG) I found sensitive content in 3 areas: - .env values: 4 secret values after the = signs (DATABASE_URL, STRIPE_SECRET_KEY, SENDGRID_API_KEY, JWT_SECRET) - Authorization header: Bearer token in the curl command - API response: personal data (login, email, name fields) Blur all of these? Or tell me which to skip. ``` You confirm, it runs ImageMagick, and reads the output image back to verify the blur landed correctly. No pixel coordinates, no manual region selection. The tricky part is getting the blur region positioned correctly. Start the blur too far left and you clip the label (`JWT_SECR` instead of `JWT_SECRET=`). Too narrow and characters peek through at the edges. The skill anchors each blur region at the delimiter character and verifies the output, catching positioning errors that a human would need to zoom in to notice. The skill asks targeted questions when the content has structure: "Blur just the values after the = signs, or the whole lines?" or "The JSON response has login, email, and name — blur all three?" You describe what to blur in human terms, the skill handles the geometry. This handles the part that's hard for humans (scanning every line of a screenshot for patterns that look like secrets) and ImageMagick handles the part that's hard for AI: pixel-level manipulation of image data. However, AI ain't perfect, so you definitely need to review the output as guide the AI to fix any problems you find. If you're familiar with the latest AI models, then you know exactly what I mean. ## Tips and Gotchas 1. Coordinates use a top-left origin in ImageMagick: `+0+0` is the upper-left corner of the image, X increases rightward, Y increases downward. If your AI returns center-origin coordinates (some vision models do), the blur will land in the wrong place. **Always specify "top-left origin" in your prompt**, if you need to rework the blurred image, when asking for coordinates. 2. **Always save output as WebP** (`-quality 85`) rather than PNG. WebP produces smaller files at equivalent quality, which matters for blog images and documentation. The `-quality 85` flag keeps the file size reasonable without visible compression artifacts. 3. One last detail about region positioning: anchor your blur at the delimiter character (`=` or `:`) and **pad to the right**, not to the left. Padding left clips variable names. Padding right just adds a safety margin past the end of the value, which is harmless. AI coordinate detection has error margins of 20-50px depending on the model, so erring slightly right is always safer than slightly left. A final caveat: Watch your model token usage. Reading and understanding images can be expensive. For example, I ran the above example in Claude code with Opus 4.6 high thinking and around 60K tokens were used. ## The Blur-Image Skill The skill referenced throughout this article handles the full pipeline: checks for ImageMagick, reads the image, detects sensitive regions, asks what you want blurred in plain language, runs the command, and verifies the output. Two modes: auto-detect (AI scans for secrets) and user-guided ("blur the email in the top right"). ```bash npx skills add jamdesk/skills --skill blur-image ``` The source is on GitHub at [jamdesk/skills](https://github.com/jamdesk/skills?ref=cms.jamdesk.com). ## Screenshots Are a Habit Worth Fixing I blur screenshots before every PR now. Every docs update, every blog post, every Slack message with terminal output. Running the skill has become muscle memory the same way running tests before pushing became muscle memory. My favorite thing to do with AI is to automate the boring parts. Your eyes are better spent on code or UI review than pixel-scanning screenshots for stray credentials. --- ## Why Static and Outdated Docs Are Holding Your Product Back URL: https://www.jamdesk.com/blog/why-static-and-outdated-docs-are-holding-your-product-back Published: 2026-02-12 *Your documentation should move at the same speed as your code. For years, software teams have treated documentation like a static artifact. A PDF-like experience frozen in time. You write once, update when someone complains or the product manager remembers, and hope developers piece together what they need. If you are in the software business, then you know this approach is broken. Modern software products are dynamic. They run multiple versions. User-specific configurations change behavior. F* > Your documentation should move at the same speed as your code. For years, software teams have treated documentation like a static artifact. A PDF-like experience frozen in time. You write once, update when someone complains or the product manager remembers, and hope developers piece together what they need. If you are in the software business, then you know this approach is broken. Modern software products are dynamic. They run multiple versions. User-specific configurations change behavior. Features work differently based on context. Yet we serve the same static documentation to everyone. Developers mentally translate generic examples into their specific situation. The word "dynamic" comes up a lot when talking about fixing docs. There are two distinct definitions, and you need both. The first: your documentation updates automatically when your code changes. The second: your documentation adapts to the person reading. The first is the foundation. Without accurate, current content, personalization is meaningless. ## Stale Docs Cost More Than You Think Your team ships a new endpoint on Monday. The docs still show the old request format on Friday. A developer integrates against the old format. Their code breaks. They open a support ticket. Your engineer spends an hour explaining the change. Stale documentation creates support tickets. Support tickets slow down your engineering team. Your engineers stop trusting the docs, which makes the staleness worse because nobody bothers updating content they do not trust. The gap between code and documentation could get wider every sprint if you do not have a good process. Nobody owns closing the gap. ## Your Docs Have a New Audience Developers are not the only ones reading your documentation anymore. Large language models are now primary consumers of your content. When a developer asks an AI assistant how to integrate your API, the model pulls from your published documentation to generate an answer. If your docs are stale, the AI gives a stale answer. The developer follows outdated instructions, hits an error, and blames your product. They never even visited your docs page directly. This changes the stakes. Your documentation quality now affects every AI-assisted interaction with your product. Every LLM-powered coding assistant, chatbot, and search engine answering questions about your API becomes a distribution channel. Accurate or not, your words get repeated at scale. ## Dynamic Definition 1: Update Docs When Code Ships The most impactful change to your documentation workflow is tying updates to your deployment pipeline. When code merges to main, trigger a process to detect doc-impacting changes and generate updates automatically. AI makes this practical today. Point a language model at your code diff and your existing docs. The model identifies what changed, which pages are affected, and what content needs rewriting. Then open a pull request with proposed changes for a human to review. ```yaml name: Update Docs on Push on: push: branches: [main] jobs: update-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 2 - name: Get changed files id: diff run: | echo "files=$(git diff --name-only HEAD~1)" >> $GITHUB_OUTPUT - name: Generate doc updates run: | node scripts/update-docs.js \ --changed-files "${{ steps.diff.outputs.files }}" \ --docs-dir ./docs - name: Create PR with doc changes uses: peter-evans/create-pull-request@v5 with: title: "docs: auto-update for latest changes" branch: docs/auto-update body: "AI-generated documentation updates based on recent code changes." ``` Here is what this looks like in practice. Your team adds a `status` field to the user API response. The pipeline detects the schema change. The AI reads the diff, finds the relevant doc page, and generates an updated response example with the new field included. ```javascript async function updateDocs(changedFiles, docsDir) { const schemaChanges = changedFiles.filter(f => f.includes('models/') || f.includes('routes/') ); if (schemaChanges.length === 0) return; for (const file of schemaChanges) { const diff = getDiff(file); const relatedDocs = findRelatedDocs(file, docsDir); for (const doc of relatedDocs) { const current = fs.readFileSync(doc, 'utf8'); const updated = await generateUpdate(diff, current); fs.writeFileSync(doc, updated); } } } ``` A human reviews the PR, approves, and the docs ship alongside the feature. No lag. No stale examples. Your CI/CD pipeline enforces accuracy, not someone remembering to update a wiki page. ## Dynamic Definition 2: Adapt Docs to the Reader The second meaning of dynamic documentation is personalization. Different developers need different things from the same page. A developer running SDK v3 does not need examples for v2. A Python developer does not want to scroll past JavaScript snippets to find relevant code. Version-aware routing detects which SDK version your reader uses and serves matching content. Language preference persistence remembers when a developer picks Python in one code example and applies the choice across every page. ```javascript function getReaderVersion() { const params = new URLSearchParams(window.location.search); return params.get('version') || localStorage.getItem('sdk-version') || 'latest'; } function setLanguagePreference(lang) { localStorage.setItem('preferred-lang', lang); document.querySelectorAll('.code-example').forEach(block => { const match = block.querySelector('[data-lang="' + lang + '"]'); if (match) { block.querySelectorAll('.lang-panel').forEach(p => p.style.display = 'none'); match.style.display = 'block'; } }); } ``` This reduces friction. A developer working with Python on SDK v2 sees Python examples for v2. No translation. No guessing. They copy, paste, and run. But personalization without accuracy is useless. Serving outdated v2 Python docs to the right person faster does not help anyone. The automated update pipeline must come first. ## Putting Both Together These two approaches work together. Automated updates keep the content accurate. Reader adaptation keeps the content relevant to each developer's context. Start with the CI pipeline. Pick one API endpoint with frequent changes. Wire up a workflow to detect modifications and generate doc updates. You can even try to measure support tickets referencing stale documentation before and after. Your documentation should move at the same speed as your code. When docs update themselves and adapt to each reader, developers spend less time fighting outdated examples and more time building. * * * ### Keep reading * [How to Write Documentation That Developers Actually Read](https://www.jamdesk.com/blog/how-to-write-documentation-that-developers-actually-read?ref=cms.jamdesk.com) * [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) — a docs-as-code platform that keeps your documentation in sync with your codebase * [Get started with Jamdesk](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com) — 14-day free trial, no credit card --- ## What is an API? URL: https://www.jamdesk.com/blog/what-is-an-api Published: 2026-01-27 *You hear the term "API" in meetings, documentation, and developer conversations. What is an API? Why does it matter to you? What API Stands For API stands for Application Programming Interface. Application: Software that performs a task. Programming: Writing code to make computers work. Interface: A boundary where two systems meet and communicate. An API lets one piece of software talk to another in a structured, predictable way. How APIs Work You send a request. You get a response. The * You hear the term "API" in meetings, documentation, and developer conversations. What is an API? Why does it matter to you? ## What API Stands For API stands for Application Programming Interface. **Application**: Software that performs a task. **Programming**: Writing code to make computers work. **Interface**: A boundary where two systems meet and communicate. An API lets one piece of software talk to another in a structured, predictable way. ## How APIs Work You send a request. You get a response. The other system's internals stay hidden from you. Say you build an app that displays weather data. You have two options. Set up weather stations across the globe, hire meteorologists, and process satellite data yourself. Or ask someone who already does that work. Here is what calling a weather API looks like: ```javascript // Request weather data for San Francisco const response = await fetch('https://api.weather.example/v1/current?city=San+Francisco'); const weather = await response.json(); console.log(weather); // { temperature: 68, conditions: "sunny", humidity: 45 } ``` One request. One response. Your app now knows the weather. ## The API Contract APIs work because they are predictable. When you call an API, you follow an agreed-upon contract. The documentation tells you: What requests you make. What format your requests use. What you get back. What happens when things fail. This contract lets you build with confidence. The API provider honors the contract. Your code keeps working. They rewrite their internals. Your code still works. ## Types of APIs **REST APIs** are most common. They use standard HTTP methods (GET, POST, PUT, DELETE) and return JSON data. ```bash # Get a user curl https://api.example.com/users/123 # Create a user curl -X POST https://api.example.com/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice", "email": "alice@example.com"}' ``` **GraphQL APIs** let you request the exact data you need. You send a query describing your requirements. ```graphql query { user(id: "123") { name email posts { title publishedAt } } } ``` **WebSocket APIs** maintain persistent connections for real-time communication. Chat apps, live scores, and stock tickers use them. ## Why Documentation Matters An undocumented API is useless. You have a well-designed API. Developers cannot figure out how to use it. They leave. They find an alternative with better docs. Good API documentation answers three questions: How do I authenticate? What endpoints exist? Where are the working examples? The best documentation explains why certain design decisions were made. It warns about common pitfalls. It provides copy-paste examples that work. ## Authentication Most APIs require authentication. You prove who you are. You prove what you are allowed to do. API keys are the most common approach. A unique string identifies your application: ```javascript const response = await fetch('https://api.example.com/data', { headers: { 'Authorization': 'Bearer your-api-key-here' } }); ``` OAuth lets users grant your application limited access to their accounts. They never share their passwords. This is how "Sign in with Google" works. ## Error Handling APIs fail. Networks fail. Servers crash. Rate limits get exceeded. Your code handles these situations. HTTP status codes tell you what happened: ```text 200 OK - Everything worked 400 Bad Request - You sent something invalid 401 Unauthorized - Your credentials are missing or wrong 404 Not Found - The resource does not exist 429 Too Many Requests - Slow down 500 Server Error - Something broke on their end ``` Good error handling matters. Your app breaks mysteriously, or your app tells users "Weather data is temporarily unavailable. Please try again." ## Start Building APIs are everywhere. They connect the services you use daily. Every time you check the weather, send a payment, or post to social media, APIs work behind the scenes. The best way to understand APIs is to use them. Pick a public API. Build something small. Make a request. Parse the response. Handle an error. An API is a conversation between computers. Now you know how to join in. * * * ### Keep reading * [How to Write Documentation That Developers Actually Read](https://www.jamdesk.com/blog/how-to-write-documentation-that-developers-actually-read?ref=cms.jamdesk.com) * [See how Jamdesk generates interactive API docs from OpenAPI specs](https://jamdesk.com/docs/api-reference/openapi-example?ref=cms.jamdesk.com) * [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) — build API documentation developers actually use --- ## How to Write Documentation That Developers Actually Read URL: https://www.jamdesk.com/blog/how-to-write-documentation-that-developers-actually-read Published: 2026-01-24 *We've all heard the stereotype that developers hate reading documentation. But if we're being honest, that’s not quite the whole story. Developers don't hate documentation; they just don't have time for bad documentation. When a guide is clear, helpful, and respects their time, it doesn't just get read—it gets bookmarked, shared, and relied upon as a source of truth. So, what's the secret sauce? What separates the docs that developers love from the ones they avoid like a legacy codebase? It usu* We've all heard the stereotype that developers hate reading documentation. But if we're being honest, that’s not quite the whole story. Developers don't hate documentation; they just don't have time for _bad_ documentation. When a guide is clear, helpful, and respects their time, it doesn't just get read—it gets bookmarked, shared, and relied upon as a source of truth. So, what's the secret sauce? What separates the docs that developers love from the ones they avoid like a legacy codebase? It usually comes down to a few core principles: truly understanding who you're writing for, designing for the way people actually navigate information, and treating your documentation with the same level of rigor as the code itself. ## Understand Your Audience The most frequent trap writers fall into is writing for themselves rather than their users. It’s easy to forget that while you’ve been living and breathing this API for months since your team built it, your users are often seeing it for the very first time. When you're deep in development, certain things start to feel like 'common sense,' but to a newcomer, they can be major roadblocks. You need to explicitly bridge those knowledge gaps by showing prerequisites and assumptions clearly. Do not be afraid to be repetitious. Sometime you need to state a warning or compatibility details in multiple sections or multiple pages to ensure that the reader sees it regardless of which page they end up at. ### Become a Product Expert You can't write great documentation for a product you don't know inside and out. To really get it right, you have to approach the product with fresh eyes, walking through the onboarding process exactly like a first-time user would. This means testing every single code example to ensure it actually runs as promised. High-quality docs require constant collaboration: * Include to the engineers who built the features. * Dive into support tickets and emails to see where users got stuck. ## Design for Navigation The reality is that developers almost never read documentation from start to finish like a novel. They’re usually searching for a very specific answer to a very specific problem. They scan headings, look for code blocks, and jump around between pages. ### Optimize for Search Most of your users will find your documentation through a search engine. To make sure they land in the right place, every page needs a descriptive title that includes the terms developers actually use. Your meta descriptions should provide a concise summary, and your headings can even be phrased as the questions a developer might have. ### Support Different Paths Because different developers come to your docs with different needs, your navigation has to accommodate multiple styles of learning. Consider these common entry points: * **The Quick Starter**: Needs a 5-minute guide to reach "Hello World". * **The Debugger**: Needs troubleshooting steps for known edge cases. ## Treat Docs as Code One of the best ways to ensure your documentation stays high-quality and sustainable is to treat it with the same respect as your codebase. ### Version Control By storing your documentation in Git alongside your source code, you unlock a suite of powerful tools. You can use pull requests to review documentation changes just like code changes, keep a clear history of what was updated and why, and even branch your docs for major upcoming releases. ### Developer Contribution When docs live in the same repository as the code, the friction for developers to contribute drops significantly. If an engineer finds an error while they're fixing a bug, they can update the docs in the same commit. ```bash # Fix bug and update docs in the same commit git commit -m "Fix user creation race condition Also updated docs to clarify that user creation is now idempotent when email already exists." ``` ### Automated Testing Just as you wouldn't ship code without tests, you shouldn't ship docs without verification: * Verify that code examples in the markdown files actually compile. * Run automated link checkers to catch 404s. ## Measure and Iterate Good documentation is never 'finished.' It’s a living product that should improve over time based on real usage data. You can start by tracking the 'age' of your pages to identify which sections are gathering dust and might need a refresh. Gathering direct feedback could also be helpful. Simple "Was this helpful?" ratings on every page can give you a quick temperature check on where you're succeeding and where you're failing. ## Enable Team Contribution The best documentation isn't the work of a lone writer—it’s a team effort. You should build processes that make it easy for engineers to contribute technical details, for support teams to share what users are struggling with, and for product managers to clarify specific use cases. The goal is to keep the contribution process as simple as possible. Complex approval workflows are where good documentation goes to die. ## The Documentation Mindset At the end of the day, great documentation comes down to a shift in mindset. It’s about treating your docs as a first-class product that deserves the same level of care, user research, and iterative improvement as the software itself. When you respect your users' time and help them succeed, they’ll notice—not by accident, but because you made a deliberate effort to understand their needs and continuously improve based on their feedback. * * * ### Keep reading * [Why Static and Outdated Docs Are Holding Your Product Back](https://www.jamdesk.com/blog/why-static-and-outdated-docs-are-holding-your-product-back?ref=cms.jamdesk.com) * [Writing MDX documentation with Jamdesk](https://jamdesk.com/docs/ai/markdown-source?ref=cms.jamdesk.com) * [Try Jamdesk free](https://www.jamdesk.com/?ref=cms.jamdesk.com) — docs-as-code with Git-based workflow and AI-ready output --- ## Build a Tiny Docs Site with Next.js in Under an Hour URL: https://www.jamdesk.com/blog/build-a-tiny-docs-site-with-next-js-in-under-an-hour Published: 2025-12-04 *A full-blown documentation platform is overkill when you're shipping something small. Docusaurus takes 15 minutes just to configure the sidebar. Mintlify wants you to sign up for an account. Sometimes you just want a few pages of markdown that look decent. We're going to scaffold a Next.js app, wire up a dead-simple "docs engine" backed by a TypeScript array, and render markdown pages. The whole thing takes about 45 minutes if you type slowly. Scaffold the Next.js app npx create-next-app@lat* A full-blown documentation platform is overkill when you're shipping something small. Docusaurus takes 15 minutes just to configure the sidebar. Mintlify wants you to sign up for an account. Sometimes you just want a few pages of markdown that look decent. We're going to scaffold a Next.js app, wire up a dead-simple "docs engine" backed by a TypeScript array, and render markdown pages. The whole thing takes about 45 minutes if you type slowly. ### Scaffold the Next.js app ```bash npx create-next-app@latest simple-docs-site cd simple-docs-site ``` Accept the defaults. We're assuming the App Router (`app/` directory), which is what newer versions of Next.js give you out of the box. ### Add some docs data No database, no CMS, no API calls. Just a TypeScript file with markdown strings. Ugly? Sure. But it works, and you can swap it for Ghost or Contentful later without touching your page components. Create a `lib/` folder in the project root (Next.js doesn't generate one for you), then add `lib/docs.ts`: ```typescript // lib/docs.ts export type Doc = { slug: string; title: string; content: string; // markdown }; export const docs: Doc[] = [ { slug: "getting-started", title: "Getting Started", content: ` # Getting Started Welcome to our docs site! This is a simple markdown-powered page. ## What you can do - Learn the basics - Click around - Extend it later with a real CMS \`\`\`bash npm install npm run dev \`\`\` `, }, { slug: "api-reference", title: "API Reference", content: ` # API Reference A fake API for demonstration: \`\`\`http GET /api/users \`\`\` Returns a list of users. `, }, ]; export function getAllDocs() { return docs; } export function getDocBySlug(slug: string) { return docs.find((doc) => doc.slug === slug); } ``` Three exports: the full list, a "get all" helper, and a "get one by slug" helper. That's your entire data layer. ### Install dependencies You need two packages: `marked` to convert markdown into HTML, and `@tailwindcss/typography` so the rendered HTML actually looks good (the `prose` classes we'll use later come from this plugin). ```bash npm install marked @tailwindcss/typography ``` Then add the plugin to your Tailwind config. If you're on Tailwind v4 (the default with latest Next.js), add this import to your CSS file, typically `app/globals.css`: ```css @import "tailwindcss"; @plugin "@tailwindcss/typography"; ``` If you're on Tailwind v3 instead, add it to the `plugins` array in `tailwind.config.ts`: ```typescript // tailwind.config.ts import type { Config } from "tailwindcss"; import typography from "@tailwindcss/typography"; export default { // ... plugins: [typography], } satisfies Config; ``` ### Create the docs list page Replace `app/page.tsx`: ```typescript import Link from "next/link"; import { getAllDocs } from "@/lib/docs"; export default function HomePage() { const allDocs = getAllDocs(); return (

Simple Docs

A tiny docs site powered by Next.js and Markdown.

    {allDocs.map((doc) => (
  • {doc.title}
  • ))}
); } ``` Maps over the docs array and renders links. Nothing else going on. ### Create the dynamic docs page Create `app/docs/[slug]/page.tsx`: ```typescript import { notFound } from "next/navigation"; import { marked } from "marked"; import { getAllDocs, getDocBySlug } from "@/lib/docs"; type DocPageProps = { params: Promise<{ slug: string }>; }; export default async function DocPage({ params }: DocPageProps) { const { slug } = await params; const doc = getDocBySlug(slug); if (!doc) { return notFound(); } const html = marked.parse(doc.content) as string; return (
← Back to docs

{doc.title}

); } export async function generateStaticParams() { const docs = getAllDocs(); return docs.map((doc) => ({ slug: doc.slug })); } ``` A couple things to note. In Next.js 15+, `params` is a Promise, so you need to `await` it before reading the slug. And `marked.parse()` can return `string | Promise` depending on configuration, so the `as string` cast keeps TypeScript happy in synchronous mode. The `generateStaticParams` function pre-renders every page at build time. If someone hits a slug that doesn't exist, they get a 404. ### Run it ```bash npm run dev ``` Visit `/` for the docs list, `/docs/getting-started` for an individual page. That's a working docs site. ### Enable server-side rendering Right now, `generateStaticParams` pre-builds every page as static HTML during `next build`. Pages are fast but frozen: if your docs content changes, visitors won't see updates until you rebuild and redeploy. For the hardcoded TypeScript array above, that's fine. But once you swap it for a CMS or database (which you probably will), you'll want pages that reflect the latest content without a full rebuild. That's where server-side rendering comes in. With SSR, each request generates fresh HTML on the server. Search engines and social media crawlers get the fully rendered page on the first request, which matters for SEO and link previews. Your content stays current without redeploying. The change is small. Remove `generateStaticParams` and add a `dynamic` export at the top of the file: ```typescript // app/docs/[slug]/page.tsx // Force server-side rendering on every request export const dynamic = "force-dynamic"; // ... rest of the component stays the same ``` If you don't need _every_ request to be fresh, ISR (Incremental Static Regeneration) is a middle ground. Replace the `dynamic` export with a revalidation interval, and keep `generateStaticParams` so pages are still pre-built at deploy time: ```typescript // Rebuild this page at most once every 60 seconds export const revalidate = 60; export async function generateStaticParams() { const docs = getAllDocs(); return docs.map((doc) => ({ slug: doc.slug })); } ``` ISR gives you the speed of static pages with content that updates automatically. For most docs sites pulling from a CMS, a 60-second revalidation window is a good default. ### Where to go from here The hardcoded TypeScript array was useful for getting something running fast, but it won't scale. Move your markdown into actual `.md` files and read them with `fs.readFileSync` at build time, or pull content from Ghost using its Content API. A sidebar and search would make navigation less painful once you have more than a handful of pages. One thing to watch: we're using `dangerouslySetInnerHTML` here, which is safe because you control the markdown source. If you ever render content from untrusted users, sanitize the HTML first with a library like [DOMPurify](https://github.com/cure53/DOMPurify?ref=cms.jamdesk.com). If you'd rather skip the plumbing entirely, [Jamdesk](https://www.jamdesk.com/?ref=cms.jamdesk.com) handles OpenAPI support, AI-ready docs, and Git-based deployment out of the box. **More reading:** * [How to Write Documentation That Developers Actually Read](https://www.jamdesk.com/blog/how-to-write-documentation-that-developers-actually-read?ref=cms.jamdesk.com) * [Jamdesk quickstart guide](https://jamdesk.com/docs/quickstart?ref=cms.jamdesk.com) --- --- *Generated: 2026-08-12T16:55:22.572Z | Static pages: 7*