Git content
This module exports and imports Drupal content as Markdown files, versioned in Git. It allows you to track content changes, sync between environments, or review diffs on any Git host.
Git Content
Export and import Drupal content as Markdown files versioned in Git.
Each entity becomes a .md file with YAML frontmatter (metadata) and a Markdown body,
stored in a content_export/ directory at the Drupal root. Track content changes with
version control, sync between environments, or review diffs on any Git host.
Requirements
- Drupal 10 or 11
- Core modules:
node,taxonomy,user,file - Optional core modules:
media,block_content,menu_link_content - Composer libraries (installed automatically):
league/html-to-markdown ^5.1league/commonmark ^2.4
- Optional: PHP
tidyextension — pretty-prints exported HTML; the module works without it.
Installation
composer require drupal/git_content
drush en git_content
The content_export/ directory is created automatically on first export. To use a different
path, add to settings.php:
$settings['git_content_export_dir'] = '../my-export';
Usage
Admin UI
Visit Administration > Git Content Sync (/admin/git-content) for a live preview
of pending changes before running an export or import.
Drush
drush git-content:export # export all (alias: gce)
drush git-content:export nodes # export one type
drush git-content:import # import all (alias: gci)
Supported types: nodes, taxonomy, media, blocks, menus, files, users.
Features
- Multilingual — default translations are processed before non-default translations.
- Checksum-based skip — unchanged files are not re-exported or re-imported.
- Correct import order — files → users → taxonomy → media → blocks → nodes → menus.
- Author preserved — stored as username, resolved on import across environments.
- Taxonomy term IDs preserved where possible so Views filters keep working.
- Menu link URLs converted from
entity:node/{id}to portableinternal:/{alias}. - Auto-generated files excluded — image style derivatives and oEmbed thumbnails are
skipped (Drupal regenerates them on render).
File structure
Language is part of the filename ({slug}.{lang}.md):
content_export/ site.yaml content/ article/ my-article.en.md my-article.es.md taxonomy/ tags/ drupal.en.md media/ image/ my-image.en.md blocks/ basic/ my-block-12.en.md menus/ main/ home.en.md files/ my-file.md users/ editor.md
File format
YAML frontmatter followed by a Markdown body. Fields after # Drupal are
Drupal-internal and ignored by static site generators.
---
type: article
lang: en
draft: false
title: My article
slug: my-article
date: 2024-01-15
author: editor
path: /my-article
taxonomy:
field_tags:
- 12
# Drupal
nid: 42
translation_of: null
checksum: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
---
Body content in **Markdown**.
Field
Description
type
Entity bundle
lang
Language code
draft
true = unpublished
date
Creation date
author
Owner's Drupal username
path
URL alias
nid / tid / mid
Entity ID (Drupal section)
translation_of
UUID of default-translation entity (non-default translations only)
checksum
SHA1 used to skip unchanged files on re-import
Submodules
git_content_layout — exports Layout Builder per-entity overrides as structured YAML.
Inline blocks are referenced by UUID. Requires layout_builder.
git_content_paragraphs — embeds Paragraphs inline in the parent .md file.
Existing paragraphs are updated in place on re-import. Requires paragraphs.
Notes
- Binary files are not exported. Only file metadata is stored; manage binaries
separately (git-lfs,rsync, etc.). - Passwords are never exported. User 1 is never overwritten on import.
- Comments are not exported or imported.