Skip to content

site:deploy — add Netlify as a deployment target alongside GitHub Pages #330

Description

@Data-Wise

Problem

/craft:site:deploy deploys Quarto/pkgdown/MkDocs sites to GitHub Pages only. Netlify is a common target for the same site types, and the migration path has sharp edges that a command could absorb.

Concretely: GitHub Pages on a private repo depends on plan tier, which is not readable from the CLI (gh api user returns plan: null; the org endpoint needs an admin:org scope a normal token lacks). Netlify sidesteps that entirely — it serves a public site from a private repo on the free tier.

Evidence from a real migration

Migrated Data-Wise/regression (Quarto course site, 126 pages) from Pages to Netlify on 2026-08-12. What bit, in order:

  1. A repo-linked Netlify build reads config from the checked-out branch only. netlify.toml existed locally and on the working branch but not on main. Per Netlify's docs an empty build command means Netlify "skips the build step and deploys files as-is" — so the failure presents as a mysterious no-op deploy, not a config error. Cost the most time of anything here.
  2. Netlify's build image has no Quarto. The build must fetch it. Where _freeze/ is committed, R is not needed and the build stays fast (170s for 126 pages).
  3. netlify.toml overrides the UI. Typing the build command into the dashboard while a toml is present creates two sources of truth that silently disagree.
  4. Double-publish. Leaving deploy.yml in place after linking Netlify publishes every commit to two hosts, which then drift.
  5. Retiring Pages needs a UI action. Deleting the workflow stops Pages updating; the old site keeps serving its last build until the deployment is removed in repo settings.

Proposed

Add a --target argument (pages | netlify), defaulting to pages so nothing changes for existing users.

For --target netlify:

  • Detect an existing netlify.toml; scaffold one if absent, with a project-type-aware build command (Quarto: fetch Quarto + quarto render; MkDocs: pip install + mkdocs build; pkgdown: pkgdown build) and the right publish dir (_site, site, docs).
  • Pre-flight: verify netlify.toml is committed and present on the deploy branch. This is the docs: fix broken links and add CLAUDE.md #1 failure and it is cheap to check.
  • Warn when a deploy.yml-style Pages workflow is still active, since that is the double-publish trap.
  • Pin the toolchain version rather than tracking latest, so an upstream release cannot change a live course/docs site with no commit.

Notes

  • The official @quarto/netlify-plugin-quarto exists but was last pushed 2023-05-10 (16 stars, not archived). A pinned fetch-and-render build command proved more current and pins the version explicitly, whereas the plugin defaults version to latest. Worth considering, but not obviously the right default.
  • Netlify's free tier moved to credit-based pricing in Sept 2025 (~300 credits/month, ~15 per production deploy ≈ ~20 deploys). That argues for keeping validation in a local gate rather than hosted CI. Per-deploy credit figure is from third-party trackers, not Netlify docs — worth re-verifying before relying on it.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions