Of course! python-docx is a fantastic and popular Python library for creating and modifying Microsoft Word (.docx) files. It's powerful, relatively easy to use, and perfect for automating the generation of reports, letters, invoices, and other documents.

Here's a comprehensive guide covering everything from installation to advanced features.
Installation
First, you need to install the library. It's available on PyPI, so you can install it using pip:
pip install python-docx
Core Concepts
Before diving into code, it's helpful to understand the structure of a .docx file and how python-docx maps to it:
- Document: The top-level object. You create a new document or load an existing one.
- Block-Level Elements: These are the main building blocks of your document. The most common ones are:
- Paragraph (
Paragraph): A block of text. Each paragraph can have its own formatting (bold, italic, alignment, etc.). - Table (
Table): A structured grid of cells. - Section (
Section): Represents a part of the document with specific page layout settings (margins, orientation, size).
- Paragraph (
- Inline-Level Elements: These are objects that live inside a paragraph, like:
- Run (
Run): A contiguous run of text with the same character-level formatting (e.g., a single word in bold). A paragraph is made up of one or more runs.
- Run (
Key Takeaway: You add Paragraphs and Tables to a Document. You format a Paragraph by adding Runs to it and setting properties on the Run or the Paragraph itself.

Creating a New Document (From Scratch)
This is the most basic task. You create a Document object and start adding content.
Example: A Simple Report
from docx import Document
from docx.shared import Pt, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
# 1. Create a new Document object
doc = Document()
# 2. Add a heading to the document
# The add_paragraph() method returns a Paragraph object
heading = doc.add_heading('Monthly Sales Report', level=1) # level 1 is Heading 1
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER # Center the heading
# 3. Add a subheading
doc.add_heading('For the Month of October 2025', level=2)
# 4. Add a paragraph
# You can add text directly to the paragraph
p = doc.add_paragraph('This report summarizes the sales performance for October. ')
p.add_run('We saw a significant increase in online sales.').bold = True # Add a bold run
# 5. Add another paragraph with a bullet point
doc.add_paragraph('Key highlights:', style='List Bullet')
doc.add_paragraph('• New product launch exceeded expectations.', style='List Bullet')
doc.add_paragraph('• Customer satisfaction scores reached an all-time high.', style='List Bullet')
# 6. Add a table
# add_table(rows, cols)
records = [
('Product A', '$12,500'),
('Product B', '$9,750'),
('Product C', '$5,430'),
('TOTAL', '$27,680')
]
table = doc.add_table(rows=1, cols=2)
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Product'
hdr_cells[1].text = 'Revenue'
for product, revenue in records:
row_cells = table.add_row().cells
row_cells[0].text = product
row_cells[1].text = revenue
# 7. Add a page break
doc.add_page_break()
# 8. Save the document
doc.save('my_report.docx')
print("Document 'my_report.docx' created successfully!")
Modifying an Existing Document
Loading an existing document is just as easy. You pass the file path to the Document() constructor.
Example: Adding a Signature to a Letter
Let's say you have a file named draft_letter.docx.
from docx import Document
# 1. Load an existing document
doc = Document('draft_letter.docx')
# 2. You can access existing paragraphs and runs
# Let's find the last paragraph and add a signature
last_paragraph = doc.paragraphs[-1]
last_paragraph.add_run('\n\nSincerely,')
last_paragraph.add_run('\nJohn Doe').italic = True
# 3. You can also modify existing text (this is more complex)
# A simple way is to find a paragraph and replace its text
for para in doc.paragraphs:
if '[Recipient Name]' in para.text:
# Clear the paragraph and add new text
para.clear()
para.add_run('Dear Ms. Jane Smith,')
# 4. Save the modified document (it's good practice to save with a new name)
doc.save('final_letter.docx')
print("Document 'final_letter.docx' created successfully!")
Formatting Text and Layout
python-docx gives you fine-grained control over appearance.

Character Formatting (on a Run)
from docx import Document
from docx.shared import RGBColor
doc = Document()
p = doc.add_paragraph()
run1 = p.add_run('This is ')
run1.bold = True
run2 = p.add_run('bold and ')
run2.italic = True
run3 = p.add_run('underlined text. ')
run3.underline = True
run4 = p.add_run('This text is large and red.')
run4.font.size = Pt(20)
run4.font.color.rgb = RGBColor(255, 0, 0) # Red
doc.save('formatted_text.docx')
Paragraph Formatting (on a Paragraph)
from docx import Document
from docx.shared import Pt, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_TAB_LEADER
doc = Document()
# Alignment
p1 = doc.add_paragraph('This paragraph is left-aligned (default).')
p2 = doc.add_paragraph('This paragraph is centered.')
p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
p3 = doc.add_paragraph('This paragraph is right-aligned.')
p3.alignment = WD_ALIGN_PARAGRAPH.RIGHT
# Indentation and Spacing
p4 = doc.add_paragraph('This paragraph has special indentation.')
p4_format = p4.paragraph_format
p4_format.left_indent = Inches(0.5)
p4_format.line_spacing = 1.75 # 1.75 line spacing
# Tabs
p5 = doc.add_paragraph('Name:\tJohn Doe\t\tScore:\t95')
tab_stop = p5.paragraph_format.tab_stops.add_tab_stop(Inches(3.5))
doc.save('paragraph_formatting.docx')
Page Layout (on a Section)
A document can have multiple sections. The sections attribute is a list, and the last one is the active one.
from docx import Document
from docx.shared import Inches, Pt
doc = Document()
doc.add_paragraph('This is the first page, using default settings.')
# Add a section break
doc.add_section()
# Modify the properties of the new section
section = doc.sections[-1]
# Change page orientation to Landscape
section.orientation = 1 # 1 for WD_ORIENT.LANDSCAPE, 0 for WD_ORIENT.PORTRAIT
# Change page margins
section.left_margin = Inches(1)
section.right_margin = Inches(1)
section.top_margin = Inches(1)
section.bottom_margin = Inches(1)
doc.add_paragraph('This is the second page, in landscape orientation with 1-inch margins.')
doc.save('page_layout.docx')
Working with Images
You can easily add images to your document.
from docx import Document
from docx.shared import Inches
doc = Document()
doc.add_heading('Image Example', level=1)
# Add an image, specifying its width
# The second argument is the width in Inches
doc.add_picture('python_logo.png', width=Inches(1.25))
doc.add_paragraph('Here is the official Python logo.')
doc.save('image_example.docx')
Useful Tips and "Gotchas"
-
Iterating Through Content: You can loop through all paragraphs and tables in a document.
for para in doc.paragraphs: print(para.text) for table in doc.tables: for row in table.rows: for cell in row.cells: print(cell.text) -
Styles: Using built-in styles (
Heading 1,List Bullet, etc.) is the best way to maintain consistent formatting. You can see available styles withprint(doc.styles). -
Complex Replacements: Simply finding and replacing text can be tricky because text is split across different
Runobjects. A robust way to handle this is to iterate through all runs and check for the text you want to replace.def replace_text_in_runs(doc, old_text, new_text): for para in doc.paragraphs: for run in para.runs: if old_text in run.text: run.text = run.text.replace(old_text, new_text) -
Headers and Footers: Access them via the
sectionobject:section.headerandsection.footer. You can add paragraphs to them just like the main document body.
Alternatives
While python-docx is excellent for creating and modifying .docx files, it's not designed for complex, pixel-perfect layout. For that, consider:
docx-mailmerge: A fantastic extension ofpython-docxspecifically for mail merge tasks. It uses<<Field_Name>>syntax in your template Word document.python-docx-template: Allows you to embed Jinja2-like syntax directly into your Word templates for more dynamic document generation.ReportLab: A powerful library for creating PDFs from scratch. It gives you ultimate control over layout but doesn't work with Word files.
For most use cases involving .docx files, python-docx is the right tool for the job.
