Features
MarkdownGit export sync
Optional content-as-code path: on publish, Externa can write published item files into a git worktree and push with a deploy key. For most headless sites, prefer outbound webhooks → CI rebuild instead.
When to use
| Need | Prefer |
|---|---|
| Rebuild Next/Nuxt/Astro | Webhooks → deploy hook |
| Files in a docs/content repo | Git export (this page) |
| One-off dump | php artisan git-export:sync --dry-run |
Enable
GIT_EXPORT_ENABLED=true
GIT_EXPORT_REMOTE_URL=git@github.com:org/content.git
GIT_EXPORT_BRANCH=main
GIT_EXPORT_SSH_KEY_PATH=/var/externa/keys/content_deploy
GIT_EXPORT_FORMAT=json
GIT_EXPORT_DRY_RUN=false
GIT_EXPORT_COLLECTION_SLUGS=*
Queue a worker. Publishing a versioned item (item.published) queues ExportCollectionItemToGitJob.
The remote may be an empty bare repository: on first export Externa initializes the branch and pushes it (#182). Clones use --template=, so locked or sandboxed filesystems work (#179).
Full sync:
php artisan git-export:sync
php artisan git-export:sync --dry-run --collection=posts
Layout
content/{collection_slug}/{item_id}.json # or .md when GIT_EXPORT_FORMAT=markdown
Threat notes
- Use a write-limited deploy key for the content repo only — not your app monorepo.
- Keep the private key on disk (
GIT_EXPORT_SSH_KEY_PATH); do not paste keys into Project settings or git. - Start with
GIT_EXPORT_DRY_RUN=trueto verify commits without push. - The worker host can push to the remote — treat that host as a secrets boundary.
- Bulk AI imports do not auto-export every row; run
git-export:syncafter large imports if needed.
Out of scope
- Bidirectional sync / pull-from-git CMS
- PR-per-publish workflows
- Replacing webhooks for static host rebuilds