@dockstat/outline-sync
v1.3.0
Published
Outline Sync is a small CLI for bidirectional synchronization between an Outline wiki and a local Markdown folder. It supports one‑time syncs, file watching, CI-friendly flows, and a targeted `push` command that compares timestamps before uploading change
Downloads
268
Readme
Outline Sync
Outline Sync is a small CLI for bidirectional synchronization between an Outline wiki and a local Markdown folder. It supports one‑time syncs, file watching, CI-friendly flows, and a targeted push command that compares timestamps before uploading changes.
Features
- Sync Outline → Local (pull documents, write frontmatter)
- Sync Local → Outline (push local changes)
pushcommand that compares local vs remoteupdatedAttimestamps- Prefers frontmatter
updatedAtover file systemmtime - Collection filtering (include/exclude)
- Custom path mapping per document
- Preserves frontmatter metadata
- CI/CD friendly workflows
- File watching for real-time pushes
- Safety checks for missing IDs or remote fetch errors
Quick install
Using bun (preferred):
bun install -g @dockstat/outline-syncOr via npm:
npm install -g @dockstat/outline-sync[!CAUTION] This package's target is set to
bunand a "bun banner" (#!/usr/bin/env bun) is also added during bundling. Make sure you have bun installed! (It's better than node anyways)
Getting started
- Initialize a sample config in your repo:
outline-sync initEdit the generated
outline-sync.config.json(see configuration below).Run a sync:
outline-sync syncConfiguration
Configuration can come from a file, environment variables, or CLI flags. Precedence: CLI args → env vars → config file.
Example outline-sync.config.json:
{
"url": "https://your-outline.com",
"token": "your_api_token",
"outputDir": "./outline-docs",
"includeCollections": ["Engineering", "Product"],
"excludeCollections": ["Archive", "Private"],
"customPaths": {
"doc-id-abc123": "../../README.md",
"doc-id-xyz789": "custom/important-doc.md"
}
}Environment variables:
export OUTLINE_URL="https://your-outline.com"
export OUTLINE_TOKEN="your_api_token"
export OUTLINE_OUTPUT_DIR="./outline-docs"CLI examples (flags take precedence):
outline-sync sync --url https://your-outline.com --token $TOKEN --output ./outline-docsCommands
outline-sync init
Create a sampleoutline-sync.config.jsonin the current directory.outline-sync sync
One-time sync: pulls documents from Outline and writes Markdown files (each with frontmatter includingupdatedAt).outline-sync watch
Watch theoutputDirfor local changes and push edits to Outline live.outline-sync ci
CI flow: perform asyncDownto cache remoteupdatedAtvalues then push local files that are newer.outline-sync push
Targeted push that compares each local file's timestamp against the remoteupdatedAtand uploads only those that appear newer. Does not require a priorsyncDown.
How change detection works
When determining if a local file should be pushed, the priority is:
- frontmatter
updatedAt(if present) - file system
mtime
That local timestamp is compared against the remote document's updatedAt. If the local timestamp is later, the file is pushed.
Notes:
pushfetches remoteupdatedAtper-document (useful for CI when nosyncDownwas done).ciwillsyncDownfirst to build a cache and reduce API calls during comparison.- Files without a valid frontmatter
idare skipped for push and surfaced to the user.
Frontmatter format
Synced files include frontmatter like:
---
id: doc-id-123
title: My Document
collectionId: col-456
parentDocumentId: null
updatedAt: 2025-01-01T12:34:56.000Z
urlId: my-document-urlid
---If you manually update the frontmatter updatedAt to a newer timestamp, the tool will honor it during comparisons.
Example usage
Sync all collections (uses config/env or CLI args):
outline-sync syncWatch and auto-push local edits (filter by collection):
outline-sync watch --include "Engineering"CI job (pull then push local changes that are newer than remote):
outline-sync ci --exclude "Private,Draft"Push local changes without an initial sync:
outline-sync push --url https://my.outline.app --token <YOUR_TOKEN> --output ./outline-docsCI/CD (GitHub Actions) example
A minimal workflow:
name: Outline Sync
on:
push:
branches: [main]
schedule:
- cron: "0 */6 * * *"
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: bun install
- run: bun run ci
env:
OUTLINE_URL: ${{ secrets.OUTLINE_URL }}
OUTLINE_TOKEN: ${{ secrets.OUTLINE_TOKEN }}
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "docs: sync from Outline"Safety notes & best practices
- Ensure frontmatter
idis present if you want files to be considered for push. pushwill perform API calls per-file to fetch remote metadata; be mindful of rate limits in CI.- If a remote fetch fails (deleted doc, permissions), that file is surfaced for manual inspection.
- Prefer scheduled
syncruns and targetedpushruns in CI to reduce unnecessary API calls.
Troubleshooting
- Unexpected pushes: inspect file frontmatter
updatedAtand filemtime. - Permission errors: verify the API token has document update scopes.
- Missing IDs: if you migrated files manually, ensure
idis present in frontmatter for push support.
Notes on collisions (collection vs document name)
If a collection and a top-level document share a sanitized title, files will be written so they do not create duplicate nested folders. For example, a root document named DockStat inside collection DockStat will be written as ./dockstat/README.md (no extra nested folder). Custom paths configured in customPaths are preserved.
Contributing
Contributions, bug reports and PRs are welcome. Please open issues in the main repo and target the dev branch for changes related to this package.
License
This package follows the repository license. See the top-level LICENSE file for details.
