---
name: package
description: "python-docx package guide for creating and editing Word .docx files from Python"
metadata:
  languages: "python"
  versions: "1.2.0"
  revision: 1
  updated-on: "2026-03-12"
  source: maintainer
  tags: "python-docx,docx,word,office,document-generation"
---

# python-docx Python Package Guide

## Golden Rule

Use `python-docx` for `.docx` generation and editing, import it as `from docx import Document`, and start from a real `.docx` template whenever styles, numbering, headers, or page layout matter. The package works on Office Open XML Word documents; it does not read legacy `.doc` files.

## Install

Pin the package version your project expects:

```bash
python -m pip install "python-docx==1.2.0"
```

Common alternatives:

```bash
uv add "python-docx==1.2.0"
poetry add "python-docx==1.2.0"
```

Notes:

- `python-docx` installs its XML dependency stack through pip; you normally do not install `lxml` separately.
- The upstream docs site is current for the API and user guide, but its install page still contains older environment guidance. Prefer modern `pip`, `uv`, or `poetry` commands plus PyPI metadata for version requirements.

## Initialize And Save

Create a new document:

```python
from docx import Document

document = Document()
document.add_heading("Quarterly Report", level=1)
document.add_paragraph("Generated by python-docx.")
document.save("report.docx")
```

Open an existing `.docx` as a template so you keep its styles, headers, footers, and page settings:

```python
from docx import Document

document = Document("template.docx")
document.add_paragraph("Inserted into a styled template.")
document.save("output.docx")
```

Write to memory instead of disk when returning a file from a web handler:

```python
from io import BytesIO
from docx import Document

document = Document()
document.add_paragraph("Hello from memory")

buf = BytesIO()
document.save(buf)
payload = buf.getvalue()
```

## Core Usage

### Paragraphs, runs, and styles

Paragraph text is made of runs. Use runs when you need mixed formatting:

```python
from docx import Document

document = Document()

paragraph = document.add_paragraph(style="Body Text")
paragraph.add_run("Normal text, ")

bold_run = paragraph.add_run("bold text")
bold_run.bold = True

italic_run = paragraph.add_run(", and italic text.")
italic_run.italic = True

document.add_paragraph("Main heading", style="Heading 1")
document.save("styled.docx")
```

### Tables

```python
from docx import Document

document = Document()
table = document.add_table(rows=1, cols=3)
table.style = "LightShading-Accent1"

header = table.rows[0].cells
header[0].text = "Name"
header[1].text = "Role"
header[2].text = "Active"

row = table.add_row().cells
row[0].text = "Ana"
row[1].text = "Editor"
row[2].text = "Yes"

document.save("table.docx")
```

### Pictures

`python-docx` supports inline pictures:

```python
from docx import Document
from docx.shared import Inches

document = Document()
document.add_picture("diagram.png", width=Inches(4.5))
document.save("image.docx")
```

### Sections, margins, headers, and footers

Use section settings for page layout. When you create a new section, its header and footer are linked to the previous section by default.

```python
from docx import Document
from docx.enum.section import WD_SECTION
from docx.shared import Inches

document = Document("template.docx")

section = document.sections[0]
section.left_margin = Inches(1)
section.right_margin = Inches(1)

new_section = document.add_section(WD_SECTION.NEW_PAGE)
new_section.header.is_linked_to_previous = False
new_section.header.paragraphs[0].text = "Appendix"

document.save("sections.docx")
```

### Read existing content

Use `paragraphs` or `tables` for simple top-level reads:

```python
from docx import Document

document = Document("existing.docx")

for paragraph in document.paragraphs:
    print(paragraph.text)
```

When content order matters, iterate the block items instead of reading paragraphs and tables separately:

```python
from docx import Document

document = Document("existing.docx")

for block in document.iter_inner_content():
    print(type(block).__name__, getattr(block, "text", ""))
```

### Comments

`1.2.0` adds a public comments API:

```python
from docx import Document

document = Document()
paragraph = document.add_paragraph("Needs review before publishing.")

document.add_comment(
    runs=paragraph.runs,
    text="Check the final wording.",
    author="Reviewer",
    initials="RV",
)

document.save("comments.docx")
```

## Configuration Notes

- There is no service authentication or global package config. The main inputs are the starting document, the style names present in that document, and the paths or file-like objects you load and save.
- Prefer a template document for anything that depends on custom styles, numbering definitions, page headers, footers, margins, or corporate branding.
- Style lookup depends on names defined in the document. Built-in Word styles use their English names in the file format, even when the Word UI is localized.
- For web apps or job runners, treat `.docx` output as a binary artifact. Save to a temp file or `BytesIO`, then upload or return that content.

## Common Pitfalls

- Import from `docx`, not `python_docx` or `python-docx`.
- `Document()` opens only `.docx` packages. Legacy `.doc` files must be converted before use.
- Assigning `paragraph.text` or `cell.text` replaces the existing runs in that container. If formatting matters, edit runs instead of overwriting the whole text.
- `document.paragraphs` and `document.tables` are not a full-fidelity traversal API. They skip nested ordering, and the paragraphs list excludes content inside revision marks like `<w:ins>` or `<w:del>`.
- `add_picture()` inserts an inline picture. If you need floating shapes or advanced drawing layout, `python-docx` does not expose that as a first-class high-level API.
- Comment anchors must align with run boundaries, and comment ranges are supported only in the main document body, not inside headers or footers.
- Table style names are easy to get wrong. Word may show a style like `Light Shading Accent 1`, while the style identifier used in code can be `LightShading-Accent1`.
- If a style is missing from the starting document, applying that style name will not produce the result you expect. Start from a template that already contains the styles you need.

## Version-Sensitive Notes For 1.2.0

- PyPI metadata for `1.2.0` requires Python `>=3.9`.
- The `1.2.0` release adds the comments feature, including `Document.add_comment()` and comment collection support.
- The current Read the Docs site serves the `1.2.0` API and user guide, but some install-page details are older than the package metadata. For environment setup, trust PyPI and the maintained project files over old `easy_install`-style instructions.
- If a project is pinned below `1.2.0`, verify feature availability before writing code copied from this guide, especially around comments and newer document traversal helpers.
