Tangly v0.2 ships richer code blocks, page chrome, and more — see what's new

Deploying

Ship your docs to Vercel, Cloudflare Pages, Netlify, Docker, or any static host.

Deploying

tangly build produces a static site at dist/ that drops onto any CDN. The adapter is auto-detected from your project; override with --adapter.

Adapter auto-detection

File present in project rootAdapter selected
vercel.jsonvercel
wrangler.toml or wrangler.jsonccloudflare
Dockerfilenode
(none)static

Vercel

The simplest path. Add vercel.json (even empty {} is fine — its presence is the auto-detect signal) and:

bash
bun x tangly build
vercel deploy ./dist

For a git-connected project, configure the build through vercel.json:

json
{
  "buildCommand": "bun x tangly build",
  "outputDirectory": "dist",
  "framework": null
}

Or set the same in the Vercel dashboard:

SettingValue
Framework PresetOther
Build Commandbun x tangly build
Output Directorydist
Install Commandbun install

Cloudflare Pages

bash
bun x tangly build
bunx wrangler pages deploy ./dist --project-name my-docs

For a git-connected project, in the Cloudflare dashboard:

SettingValue
Framework presetNone
Build commandbun x tangly build
Build output directorydist
Root directory/ (or your subdir)

A wrangler.toml at the project root triggers auto-detect:

name = "my-docs"
compatibility_date = "2026-04-29"

[site]
bucket = "./dist"

Netlify

No special adapter — Netlify serves any static directory. Add netlify.toml:

[build]
  command = "bun x tangly build"
  publish = "dist"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Or via the dashboard with the same build command and publish directory.

Plain static (S3, R2, GitHub Pages, nginx)

bash
bun x tangly build
# Upload dist/ to your host.

# S3:
aws s3 sync dist/ s3://my-bucket --delete

# rsync to a VPS:
rsync -avz --delete dist/ user@host:/var/www/docs/

# GitHub Pages: commit dist/ to the gh-pages branch.

For nginx, point the server root at dist/:

server {
  listen 80;
  server_name docs.example.com;
  root /var/www/docs;
  index index.html;

  location / {
    try_files $uri $uri/index.html =404;
  }
}

Docker

Drop a Dockerfile to trigger the node adapter (still static today):

FROM oven/bun:1.2-alpine AS build
WORKDIR /app
COPY . .
RUN bun install --frozen-lockfile
RUN bun x tangly build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

nginx.conf:

server {
  listen 80;
  root /usr/share/nginx/html;
  location / {
    try_files $uri $uri/index.html =404;
  }
}

Build and run:

bash
docker build -t my-docs .
docker run -p 8080:80 my-docs

GitHub Pages

yaml
name: Deploy docs
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install --frozen-lockfile
      - run: bun x tangly build --base /REPO-NAME
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v4

The --base flag is required when serving under https://USER.github.io/REPO/.

Subpath hosting

Deploy under /docs instead of the host root:

bash
bun x tangly build --base /docs

Every internal link, asset URL, sitemap entry, llms.txt URL, and Pagefind result is prefixed with the base. See Hosting docs at a subpath for the five common strategies — building into a parent site’s public/, edge rewrites on Vercel/Netlify/Cloudflare, nginx reverse proxy, and GitHub Pages project repos.

What gets built

  • Directorydist/
    • index.html redirects to first nav page
    • introduction/index.html
    • introduction.md raw source for AI agents
    • guides/<slug>/index.html
    • guides/<slug>.md
    • Directoryimages/ copied verbatim from project root
    • Directorylogo/
    • Directorypublic/
    • Directorypagefind/ search index
    • sitemap.xml
    • robots.txt
    • llms.txt for AI crawlers
    • llms-full.txt

Drafts (draft: true in frontmatter) are excluded. noindex: true pages are emitted but excluded from sitemap.xml, llms.txt, llms-full.txt, the per-page .md files, and the Pagefind index.

Markdown for agents

Tangly emits a raw-Markdown twin of every page (<slug>.md alongside <slug>/index.html) so coding assistants can fetch source instead of rendered HTML — ~10× token reduction. Works on any static host with no extra config: append .md to any URL and you get the source.

For same-URL content negotiation (Accept: text/markdown returns Markdown, browsers still get HTML), add a one-line CDN rewrite — see Markdown for agents for Vercel, Cloudflare, and Netlify recipes.

Pre-deploy checklist

bash
bun x tangly check --strict   # exit 0 means clean
bun x tangly build
bun x tangly preview          # smoke test in browser

CI: drop the same three commands into your pipeline. tangly check --strict --json plays well with annotation scripts.

↑↓ navigate open esc close