How to indent multiple lines in Python

Struggling with Python indentation? Learn to indent multiple lines with various methods, tips, real-world examples, and debugging help.

How to indent multiple lines in Python
Published on: 
Fri
Feb 20, 2026
Updated on: 
Mon
Apr 6, 2026
The Replit Team

Proper indentation in Python is essential for code execution and readability. It defines the structure of your loops, functions, and classes and is a fundamental concept for every developer.

In this article, you'll learn several techniques to indent multiple lines efficiently. We'll cover practical tips, real-world applications, and advice to debug common indentation errors.

Basic indentation with spaces

text = """First line
Second line
Third line"""
indented_text = ""
for line in text.split("\n"):
indented_text += " " + line + "\n"
print(indented_text)--OUTPUT--First line
Second line
Third line

This approach manually adds indentation by processing each line of a string individually. The code first uses text.split("\n") to break the multi-line string into a list of separate lines. This gives you an iterable collection to work with, similar to how commenting in Python helps organize and structure your code.

The for loop then processes each line from that collection. Inside the loop, the expression " " + line concatenates four spaces to the front of the line, creating the indentation. This method is a foundational technique for programmatically controlling whitespace in your text output.

Standard indentation techniques

Moving past the basic loop, Python provides several powerful, built-in functions and syntax features to make indenting multiple lines much simpler.

Using the textwrap.indent() function

import textwrap

text = """First line
Second line
Third line"""
indented_text = textwrap.indent(text, prefix=" ")
print(indented_text)--OUTPUT--First line
Second line
Third line

The textwrap module offers a more direct way to handle text formatting. Its textwrap.indent() function is specifically designed for this task, applying a given prefix to every line in a string and saving you from writing a manual loop.

  • The function takes the text as its first argument.
  • The prefix argument specifies the string to add, such as " " for standard indentation.

This approach is cleaner and memory-efficient than manually iterating through each line. It's the recommended method for simple, block-level indentation tasks.

Using string methods with splitlines() and join()

text = """First line
Second line
Third line"""
indented_text = "\n".join(" " + line for line in text.splitlines())
print(indented_text)--OUTPUT--First line
Second line
Third line

This approach combines two string methods into a compact one-liner. It’s a common Pythonic pattern that chains splitlines() and join() to manipulate text efficiently.

  • First, text.splitlines() breaks the string into a list, with each line as an item.
  • A generator expression then iterates through this list, prepending four spaces to each line.
  • Finally, "\n".join() stitches the newly indented lines back together into a single string, separated by newlines.

Using multi-line string formatting with triple quotes

indent = " " * 4
indented_text = f"""{indent}First line
{indent}Second line
{indent}Third line"""
print(indented_text)--OUTPUT--First line
Second line
Third line

This technique leverages Python's f-strings and triple quotes for direct, inline indentation. It's a highly readable approach when your text is static and you want to see the final structure right in your code. For more advanced techniques with multiline strings in Python, you can explore additional formatting options.

  • First, you create a variable like indent = " " * 4 to hold your indentation string.
  • Then, within a triple-quoted f-string, you place {indent} at the beginning of each line you want to indent.

This method is visually clean because the formatting is explicit and part of the string itself, making your code's intent immediately clear.

Advanced indentation approaches

For more control over your text formatting, you can move beyond standard functions and create specialized solutions for complex or repetitive indentation needs.

Creating a context manager for indentation

class Indenter:
def __init__(self, level=0):
self.level = level

def __enter__(self):
self.level += 1
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.level -= 1

def print(self, text):
print(" " * self.level + text)

with Indenter() as indent:
indent.print("First level")
with indent:
indent.print("Second level")--OUTPUT--First level
Second level

A context manager provides a robust way to handle resources that need setup and teardown—in this case, indentation levels. The Indenter class lets you use a with statement to automatically manage indentation for nested blocks of text. This approach is perfect for generating structured output like code or logs where hierarchy matters.

  • The __enter__ method runs when you enter a with block, increasing the indentation level.
  • When the block is exited, the __exit__ method runs, decreasing the level back down.
  • The custom print method applies the current indentation before printing.

Using regex for selective indentation

import re

text = """def function():
# This is already indented
pass # This needs indentation"""

# Only indent lines that don't already have whitespace at the beginning
indented_text = re.sub(r"^(\S)", r" \1", text, flags=re.MULTILINE)
print(indented_text)--OUTPUT--def function():
# This is already indented
pass # This needs indentation

Regular expressions offer precise control for complex situations. This method uses re.sub to add indentation only where it's needed, leaving already indented lines untouched. It’s a powerful way to format text conditionally, especially when dealing with pre-formatted code snippets.

  • The pattern r"^(\S)" targets any line that starts with a non-whitespace character.
  • The re.MULTILINE flag makes the ^ anchor match the beginning of each line.
  • The replacement string r" \1" inserts four spaces and then reinserts the original character, indenting only the lines that match the pattern.

Creating a reusable indentation utility

def indent_block(text, indent_level=1, indent_char=" "):
prefix = indent_char * indent_level
if isinstance(text, list):
return [prefix + line for line in text]
else:
return "\n".join(prefix + line for line in text.splitlines())

code_block = "for i in range(3):\n print(i)"
print(indent_block(code_block, indent_level=2))--OUTPUT--for i in range(3):
print(i)

This approach packages the logic into a versatile function, indent_block, that you can reuse across your projects. It’s built for flexibility, handling both multi-line strings and lists of strings automatically. This saves you from writing repetitive formatting code for different scenarios.

  • The function intelligently checks the input type with isinstance(), applying the indentation correctly whether you provide a single block of text or pre-split lines.
  • You can customize the indentation with the indent_level and indent_char arguments, making it adaptable to any coding style or formatting need.

Move faster with Replit

Replit is an AI-powered development platform where all Python dependencies come pre-installed, so you can skip setup and start coding instantly. While mastering individual techniques is important, Agent 4 helps you move from piecing together functions to building complete applications.

Instead of manually formatting text, you can describe the app you want to build, and the Agent will take it from an idea to a working product:

  • A documentation helper that takes raw code and automatically applies consistent indentation for embedding in tutorials.
  • A log file beautifier that parses unstructured logs and indents nested events to make debugging easier.
  • A configuration generator that creates structured YAML or JSON files from a simple list of settings, handling all the necessary nesting and spacing.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

Even with the right techniques, you might run into a few common indentation issues, but they're usually straightforward to fix.

Fixing the TabError: Mixing tabs and spaces

Python raises a TabError when you mix tabs and spaces for indentation within the same code block. Because different text editors interpret the width of a tab character differently, mixing them creates ambiguity that Python's interpreter can't resolve.

The best practice, recommended by the PEP 8 style guide, is to configure your code editor to use spaces exclusively. Most editors have a setting to automatically convert tabs to a set number of spaces, typically four, which prevents this error entirely.

Debugging IndentationError: Inconsistent indentation levels

An IndentationError is one of the most frequent errors for new Python developers. It occurs when a line of code has an incorrect level of indentation, either too much or not enough, breaking the logical structure.

You'll often see this with control structures. For example, an else statement might not be aligned with its corresponding if, or a line inside a loop might be indented differently from the others. The fix is to ensure every line in a block is indented consistently.

Handling unexpected indentation in multiline strings with dedent()

Sometimes the problem isn't in your code's logic but in your multiline strings. When you define a triple-quoted string inside an indented block, like a function, the string itself captures that leading whitespace.

To clean this up, you can use the textwrap.dedent() function. It intelligently removes the common leading whitespace from every line in the string. This is incredibly useful for preserving the relative indentation within your string while removing the indentation from the surrounding code.

Fixing the TabError: Mixing tabs and spaces

This error is a classic "gotcha" where invisible characters cause visible problems. It happens when you inadvertently mix tabs and spaces for indentation, which Python strictly forbids. The following function demonstrates how easily this can happen and what it looks like.

def calculate_sum(numbers):
total = 0 # This line uses a tab
for num in numbers: # This line uses spaces
total += num
return total

print(calculate_sum([1, 2, 3]))

The calculate_sum function fails because the total = 0 line is indented with a tab, while the following for loop uses spaces. This mix of invisible characters triggers the TabError. The corrected version below shows how to resolve this.

def calculate_sum(numbers):
total = 0
for num in numbers:
total += num
return total

print(calculate_sum([1, 2, 3]))

The corrected code resolves the error by using consistent spacing. By replacing the tab with four spaces, every line in the calculate_sum function is indented uniformly, satisfying Python's structural rules. This error often appears when you copy and paste code, as different editors can introduce a mix of tabs and spaces. The best defense is to configure your editor to always use spaces for indentation, which prevents the problem from happening in the first place.

Debugging IndentationError: Inconsistent indentation levels

An IndentationError occurs when lines in the same code block don't align. Python relies on consistent spacing to define its structure, so even a single misplaced space can break your script. The process_data function below demonstrates this common issue.

def process_data(data):
if data:
result = []
for item in data:
filtered = item.strip() # 3 spaces instead of 4
return result
return None

Inside the for loop, the filtered = item.strip() line has an unexpected amount of indentation. This misalignment breaks the logical block, causing the error. The corrected code shows how to fix this alignment.

def process_data(data):
if data:
result = []
for item in data:
filtered = item.strip() # Consistent 4 spaces
return result
return None

The fix is simple: the corrected code aligns filtered = item.strip() properly within the for loop. By using a consistent four spaces, every statement inside the block shares the same indentation level, which satisfies Python's structural rules. This error often appears when refactoring or copying code, so it's a good habit to double-check alignment inside loops and conditional statements to keep your script running smoothly.

Handling unexpected indentation in multiline strings with dedent()

When you define a multiline string inside an indented function, the string itself inherits that extra whitespace. This can mess up your output, especially with formats like HTML where spacing is significant. The get_html function below shows this problem in action.

def get_html():
html = """
<div>
<h1>Title</h1>
</div>
"""
return html.strip()

Here, the html.strip() method only cleans up the outer whitespace of the entire string block, leaving the unwanted indentation on each inner line. The corrected code below shows how to address this properly.

import textwrap

def get_html():
html = textwrap.dedent("""
<div>
<h1>Title</h1>
</div>
""")
return html.strip()

The corrected code uses textwrap.dedent() to remove the common leading whitespace from every line in the string. Unlike strip(), which only cleans the outer edges of the entire string block, dedent() preserves the string's internal structure while removing the unwanted indentation from the surrounding code.

This is crucial when you define formatted text like HTML or YAML inside an indented function, as it ensures your output isn't skewed by extra spaces.

Real-world applications

Mastering indentation isn't just about avoiding errors; it’s about building tools that generate clean, structured output in practical applications.

Creating a simple CLI tree view with indentation

You can build a simple command-line tree view by writing a recursive function that adjusts indentation based on the data's nesting level.

def display_tree(items, level=0):
for item in items:
print(" " * level + "├── " + item["name"])
if "children" in item and item["children"]:
display_tree(item["children"], level + 1)

file_tree = [
{
"name": "project",
"children": [
{"name": "main.py"},
{"name": "data", "children": [{"name": "config.json"}]}
]
}
]

display_tree(file_tree)

This code uses recursion in Python—a technique where a function calls itself—to print a nested data structure. The display_tree function processes a list of items, and the level parameter keeps track of the current depth to calculate the indentation.

  • For each item, it prints the name, prefixed with spaces based on its level.
  • If an item contains a children key, the function calls itself with the nested list and an incremented level.

This process repeats until all nested items are printed, creating a visual tree from the data.

Creating a simple Python code formatter with indent_level

You can build a simple code formatter by creating a function that manages an indent_level to apply correct spacing based on syntax cues.

def format_simple_code(code):
lines = code.split('\n')
formatted_lines = []
indent_level = 0

for line in lines:
stripped = line.strip()
if not stripped: # Skip empty lines
continue

formatted_lines.append(' ' * indent_level + stripped)

if stripped.endswith(':'):
indent_level += 1

return '\n'.join(formatted_lines)

code = """def greet(name):
message = f"Hello, {name}!"
print(message)"""

print(format_simple_code(code))

This format_simple_code function rebuilds your code with proper spacing. It iterates through each line, using an indent_level variable to track the current depth.

  • Before adding a line, it prepends the correct number of spaces based on the current indent_level.
  • After adding the line, it checks if the line ends with a colon (:). If it does, it increments the indent_level for all subsequent lines.

This simple heuristic allows the function to automatically format blocks that follow statements like def or for, creating structured output from unformatted code using techniques similar to vibe coding.

Get started with Replit

Turn your knowledge into a real tool with Replit Agent. Try "a Python script that auto-formats code snippets" or "a utility that converts JSON to an indented tree view".

The Agent writes the code, tests for errors, and deploys your app. Start building with Replit.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.