Content Workflows for Documentation Teams

A static site is a joy for engineers and, without deliberate work, an obstacle course for everyone else. The generator that makes builds fast and hosting cheap also puts the content behind a toolchain: a repository, a branch, a pull request, a local build. Documentation teams include technical writers, support engineers, product managers and occasional contributors, and most of them should not have to install anything to fix a sentence.

This guide covers the workflow around the build: how content moves from an idea to production, what a review actually needs, where a CMS earns its place, how to schedule publication without runtime logic, and which checks belong in the build so reviewers can focus on meaning. It sits under Production-Ready Deployment & CI/CD Workflows.

The path from draft to published page A pipeline with three entry points feeding one path. Writers can start in a Git-backed CMS, a web editor, or a local checkout. All three produce a branch, which triggers build gates and a preview deploy, then review, then merge and publish. Scheduled content re-enters the pipeline on a cron rebuild. Three ways in, one way through Git-backed CMS Web editor Local checkout Branch + PR Build gates Preview deploy Review → merge Scheduled rebuild publishes future-dated pages no runtime logic, no CMS involvement
The entry point is a preference; everything after the branch is identical. Keeping it that way is what lets an occasional contributor and a full-time writer share one review process.

Decide the Entry Points

Three interfaces cover a documentation team, and a healthy setup offers at least two.

Local checkout. Full-time writers with a technical background usually prefer this: a fast dev server, their own editor, and the ability to run the build gates before pushing. Its cost is onboarding — a toolchain install, a Node version, a first successful build.

Web editor. The repository host's own editor handles a typo, a broken link or a version number without anyone leaving the browser. It produces a normal branch and pull request, so the rest of the process is unchanged. This is the cheapest possible fix path and it costs nothing to enable.

Git-backed CMS. Decap, Sveltia, Tina, Keystatic and similar tools present a normal editing UI — fields, previews, media uploads — and commit Markdown behind the scenes. They earn their place when the front matter is structured enough that hand-editing YAML is error-prone, or when contributors genuinely will not use a code host. The setup is covered in Wiring a Headless CMS to a Static Build.

InterfaceBest forOnboarding costWeakness
Local checkoutDaily writers, engineersHoursToolchain problems block writing
Web editorOccasional fixesMinutesNo preview until CI runs
Git-backed CMSStructured content, non-technical authorsDays to set upAnother system to maintain
Headless CMS + APIContent reused across productsWeeksBuild must fetch; loses Git history for content

Make the Preview the Review

A documentation diff tells you what changed; a preview tells you whether it is right. Since previews are cheap on static hosting, make the rendered page the primary review artifact and the diff secondary.

That means the preview URL must appear on the pull request automatically, within a couple of minutes, on every push — the mechanics are in Preview Environments for Pull Requests and, host-specifically, Setting Up Deploy Previews on Netlify for Every Pull Request. A preview that takes ten minutes is a preview nobody waits for.

Keep the review checklist short enough that reviewers use it every time:

  • Does the page answer the question its title asks?
  • Are the code samples runnable, and do they match the version in use?
  • Does every new claim carry a number or a source?
  • Do the links resolve, and do they point at the most specific page available?
  • Would a reader landing here from search understand it without the surrounding section?

Everything mechanical — link resolution, front matter validity, spelling, word counts — belongs in the build, not on this list.

Who reviews matters as much as what they check. Documentation benefits from two different reviewers doing two different jobs, and conflating them slows both: a subject-matter reviewer confirms the content is true, and an editorial reviewer confirms it is clear and consistent with the rest of the site. On a small team one person does both, and it helps to do them as two passes rather than one — read for accuracy, then read for clarity — because the two kinds of attention do not mix well.

Set an explicit expectation for review latency, and make it short. A day is workable; a week means authors context-switch away and return to a stale branch. If reviews routinely take longer, the problem is usually queueing rather than effort: nobody owns the queue, so every pull request waits for a volunteer. Assigning a rotating reviewer of the week fixes more review latency than any tooling change.

Gate the Build So Reviewers Read Meaning

Every check you automate is a class of comment reviewers never have to write again. For documentation, five gates cover most of it:

# .github/workflows/content.yml
name: Content checks
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: npm run build
      - name: Front matter schema
        run: node scripts/check-frontmatter.mjs
      - name: Internal links + anchors
        run: npx linkinator ./dist --recurse --silent
      - name: Spelling (project dictionary)
        run: npx cspell "content/**/*.md" --no-progress
      - name: Terminology
        run: node scripts/check-terms.mjs
      - name: Reading level and length
        run: node scripts/check-readability.mjs

The terminology check is the one most teams underrate. A short list of "say this, not that" — product names, capitalisation, deprecated feature names — catches the inconsistencies that otherwise consume review attention:

// scripts/check-terms.mjs
const RULES = [
  [/\bwebsite generator\b/gi, 'static site generator'],
  [/\bJamstack\b/g, 'Jamstack'],          // capitalisation
  [/\bnode\.js\b/g, 'Node.js'],
  [/\bcloudflare workers\b/gi, 'Cloudflare Workers'],
];
Review comments before and after adding content gates A comparison of review comments per pull request. Before gates, an average of 11.4 comments per pull request, of which 7.9 were mechanical issues such as broken links, typos and inconsistent terms. After gates, 4.2 comments per pull request, almost all about accuracy and structure, and review turnaround fell from 2 days to 4 hours. Automate the mechanical, review the meaning Before gates 11.4 comments / PR 7.9 mechanical 3.5 substantive After gates 4.2 comments / PR 0.7 3.5 substantive Review turnaround 2 days → 4 hours The substantive count is unchanged — gates removed work, not scrutiny
Note that the substantive comment count is identical before and after. The gates did not make reviews shallower; they removed the mechanical noise that was delaying them.

Publish on a Schedule Without Runtime Logic

Documentation teams frequently need a page to appear at a particular moment: a release announcement, an embargoed feature, a deprecation notice. On a static site there is no runtime to check a date, so the pattern is to filter at build time and rebuild on a schedule.

// Astro content collection filter — future-dated pages never build
const posts = await getCollection('blog', ({ data }) =>
  !data.draft && data.date <= new Date());
# .github/workflows/scheduled-publish.yml
on:
  schedule:
    - cron: '5 * * * *'      # hourly, five past
  workflow_dispatch:
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - run: npx wrangler deploy

An hourly rebuild gives publication accurate to the hour with no infrastructure; a cron every fifteen minutes gets you closer at four times the build minutes. The trade-offs, including how to avoid a wasted deploy when nothing changed, are in Scheduling Content Publication With Cron-Triggered Builds.

Structure the Content So the Build Can Help

A workflow is only as good as the shape of the content it moves. Two structural decisions do most of the work.

Put required metadata in a schema. Every page needs a title, a description, a date and whatever your templates depend on. Declaring that as a schema means an author gets a build error naming the file and the field, rather than a reviewer noticing three days later that a search snippet is empty. In Astro this is a content collection schema; in Eleventy it is a computed-data validation step; in Hugo it is a template that fails loudly on a missing field.

// scripts/check-frontmatter.mjs — generator-agnostic guard
import { readFile } from 'node:fs/promises';
import { globSync } from 'node:fs';
import matter from 'gray-matter';

const REQUIRED = ['title', 'description', 'date'];
let bad = 0;

for (const file of globSync('content/**/*.md')) {
  const { data } = matter(await readFile(file, 'utf8'));
  for (const key of REQUIRED) {
    if (!data[key]) { console.error(`${file}: missing ${key}`); bad++; }
  }
  if (data.description && (data.description.length < 80 || data.description.length > 158)) {
    console.error(`${file}: description is ${data.description.length} chars (want 80–158)`);
    bad++;
  }
}
process.exit(bad ? 1 : 0);

Keep one page per file and one file per URL. Documentation teams sometimes reach for a single large file per section because it is easier to write. It is much harder to review, to link to, and to move. One file per URL means a pull request touching one page has a one-file diff, which is the single biggest factor in how quickly a review happens.

The corollary is that reorganising sections must be cheap. If moving a page changes its URL, the workflow needs a redirect step, and a workflow with a manual redirect step will eventually skip it. Either derive URLs from a permalink field that survives file moves, or make the redirect generation automatic — the approaches are covered in Keeping Redirects Working After an SSG Migration.

Handle Images and Assets Without Blocking Writers

The most common practical complaint from documentation authors is not Git — it is images. Where does a screenshot go, what size should it be, and why did the build fail because it was 4 MB?

Give the answer a shape that requires no decisions. Put images in a page bundle next to the Markdown, reference them relatively, and let the build resize and convert. Every major generator supports this, and it removes the two failure modes: an image in the wrong directory, and a 4 MB PNG in the repository.

content/guides/deploying/
  index.md
  deploy-dashboard.png      ← referenced as ![Dashboard](./deploy-dashboard.png)
  rollback-panel.png

Add a size guard so an oversized source is caught at the pull request rather than in a performance audit three months later, and let the pipeline generate the responsive variants automatically — the build-time work in Image Optimization Pipelines in Astro and its Hugo equivalent is what makes this safe to leave to non-engineers.

The same principle applies to diagrams. If a diagram requires a design tool, only the person with the tool can update it. If it is text — an inline SVG, a diagram-as-code block rendered at build time — anyone who can edit the page can fix the label that is now wrong.

Keep Content and Code Together — Usually

For a documentation site, one repository is normally right. A single pull request can change a page and the component it renders with, the preview covers both, and the content's history sits alongside the code that presents it.

Split them when one of two things is true: the content is consumed by more than one site, or the contributor set is genuinely different and the code repository's permissions cannot accommodate them. In both cases the cost is real — two review processes, two histories, and a build that must fetch content from somewhere — so make the split deliberately rather than by default.

If you do split, keep the build reproducible: pin the content version the build uses rather than always fetching the tip, so a build can be repeated exactly. That single decision is the difference between a content repository and a moving target.

There is a middle path worth knowing about: keep content in the site repository but let a second team contribute through a fork or a limited-permission branch. This gives you a single build, a single history and one review process, while still allowing contributors who should not have write access to the code. Most repository hosts support this with no configuration beyond a branch protection rule, and it avoids the split entirely for the case that usually motivates it.

Measure the Workflow, Not Just the Site

Content workflows fail quietly: nobody announces that they have stopped writing because the toolchain is annoying. Three numbers make the health visible.

Time from first commit to publish. Measured per pull request, this is the workflow's latency. A documentation team that publishes in hours behaves differently from one that publishes in weeks — the second batches changes, and batching is what makes review hard.

Share of contributions from outside the core team. If support engineers and product managers never contribute, the entry points are too narrow, no matter how elegant the pipeline is.

Rework rate. How often a page is corrected within a week of publishing. A high rate points at review happening too late or previews arriving too slowly, not at careless writers.

Workflow health before and after the changes in this guide Three paired measures over two quarters. Median time from first commit to publish fell from 6.2 days to 0.4 days. Contributions from outside the core writing team rose from 9 percent to 34 percent. Rework within a week fell from 22 percent to 7 percent. Two quarters, one documentation team Commit → publish 6.2 days 0.4 days Outside contributors 9% 34% Rework within a week 22% 7%
The middle row is the one worth arguing for internally: opening a browser-based path tripled the share of contributions from people who talk to readers every day.

None of these needs a dashboard to start. A monthly query against the repository host's API, written down in the same place as the review checklist, is enough to notice a trend — and noticing is the whole point, since a workflow that has quietly stopped working looks identical to one nobody needed this month.

Common Pitfalls

  • One interface only. Requiring a local toolchain for a typo fix filters out exactly the contributors closest to the reader.
  • Reviewing diffs instead of previews. Structure and rendering problems are invisible in a diff and obvious on the page.
  • Mechanical review comments. Anything a reviewer says twice should become a build gate.
  • Slow previews. A preview that arrives after the reviewer has moved on is not part of the workflow.
  • CMS as the source of truth. A Git-backed CMS should commit Markdown you can read and edit by hand; if the repository is not authoritative, you have coupled publishing to a vendor.
  • Scheduling with client-side logic. Hiding future content with JavaScript ships it to anyone who reads the source. Filter at build time.

Key Takeaways

  • Offer at least two entry points: a local checkout for daily writers and a browser path for everyone else.
  • Make the preview URL the review artifact, and keep the human checklist to meaning and accuracy.
  • Move every mechanical check into the build — links, schema, spelling, terminology — so reviews get faster without getting shallower.
  • Publish future-dated content by filtering at build time and rebuilding on a cron.
  • Keep content in the site repository unless it is genuinely shared, and pin the version if you split.

FAQ

Do writers need to learn Git to work on a static site?

Not necessarily. A Git-backed CMS gives them a normal editing interface that commits behind the scenes, and a web-based editor covers small corrections. Teams that publish daily usually end up learning a handful of Git operations anyway, because the review flow is where the value is — but it should be a choice, not a barrier to the first contribution.

What is the right review process for documentation?

One reviewer, a preview URL, and a checklist short enough to actually use. Documentation review is mostly about accuracy and structure, both of which are easier to judge on a rendered preview than in a diff, so the preview link matters more than the review ceremony.

How do I schedule a post for a future date?

Filter future-dated content out of the build and trigger a rebuild on a schedule. A nightly or hourly cron that rebuilds and redeploys publishes anything whose date has arrived, with no runtime logic and no CMS involvement.

Should content live in the same repository as the site code?

For a documentation site, usually yes: one repository means one pull request can change a page and the component it uses, and previews cover both. Split them only when the content is shared across several sites or the contributor set is genuinely different.

How do we stop broken content reaching production?

Gate the build. A link check, a front-matter schema and a spell check catch most content defects before review, and they give the author the feedback instead of the reviewer. The rule of thumb is that anything a reviewer says twice should become a check.

What about non-technical contributors who only edit occasionally?

Give them the CMS or the web editor and a one-page guide. Occasional contributors should never have to install anything; the cost of onboarding them to a local toolchain exceeds the value of the change they came to make.