Adding rows to the beginning of a DataFrame is a common operation, but it requires understanding how Pandas works internally. DataFrames are column-oriented and immutable in size, meaning every row addition creates a new object rather than modifying the existing one in place. Choosing the right approach prevents performance issues, avoids deprecated method warnings, and keeps your code clean.
In this guide, you will learn how to prepend rows using the recommended pd.concat() approach, understand why some alternatives should be avoided, and recognize the critical performance difference between adding rows one at a time versus in batch.
The Standard Solution: pd.concat()
Create a single-row DataFrame for the new data and concatenate it before the original DataFrame:
import pandas as pd
df = pd.DataFrame({
'Name': ['Alice', 'Bob'],
'Age': [25, 30]
})
new_row = pd.DataFrame([{'Name': 'Charlie', 'Age': 35}])
df_updated = pd.concat([new_row, df], ignore_index=True)
print(df_updated)Output:
Name Age
0 Charlie 35
1 Alice 25
2 Bob 30The new row appears at the top because it comes first in the pd.concat() call. The ignore_index=True parameter resets the index to a clean sequential sequence (0, 1, 2) instead of preserving the original index values from each DataFrame.
Adding Multiple Rows at Once
The same pattern works for prepending several rows:
import pandas as pd
df = pd.DataFrame({'Name': ['Alice'], 'Age': [25]})
new_rows = pd.DataFrame([
{'Name': 'Bob', 'Age': 30},
{'Name': 'Charlie', 'Age': 35}
])
df_updated = pd.concat([new_rows, df], ignore_index=True)
print(df_updated)Output:
Name Age
0 Bob 30
1 Charlie 35
2 Alice 25Alternative: Using .loc[] with an Index Trick
For simple cases with integer-indexed DataFrames, you can assign to index position -1 and then sort:
import pandas as pd
df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})
df.loc[-1] = ['Charlie', 35]
df = df.sort_index().reset_index(drop=True)
print(df)Output:
Name Age
0 Charlie 35
1 Alice 25
2 Bob 30Methods to Avoid
The Removed .append() Method
The .append() method was removed in Pandas 2.0. Code that uses it will raise an error in modern versions:
import pandas as pd
df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})
try:
df = df.append({'Name': 'Charlie', 'Age': 35}, ignore_index=True)
except AttributeError as e:
print(f"Error: {e}")Output:
Error: 'DataFrame' object has no attribute 'append'Replace any .append() calls with pd.concat() as shown in the standard solution above.
Critical Performance Consideration: Avoid Loops
Adding rows inside a loop is one of the most common performance mistakes in Pandas. Each pd.concat() call copies all existing data into a new DataFrame, so adding n rows one at a time results in quadratic (O(n squared)) time complexity:
import pandas as pd
import time
start = time.time()
df = pd.DataFrame(columns=['Name', 'Age'])
for i in range(1000):
new_row = pd.DataFrame([{'Name': f'User_{i}', 'Age': 20 + i}])
df = pd.concat([new_row, df], ignore_index=True)
slow_time = time.time() - start
start = time.time()
rows = []
for i in range(1000):
rows.append({'Name': f'User_{i}', 'Age': 20 + i})
df = pd.DataFrame(rows)
fast_time = time.time() - start
print(f"Loop concat: {slow_time:.4f}s")
print(f"Batch create: {fast_time:.4f}s")
print(f"Batch is ~{slow_time / fast_time:.0f}x faster")Output:
Loop concat: 0.5423s
Batch create: 0.0012s
Batch is ~452x fasterThe batch approach collects all data in a plain Python list, then creates the DataFrame in a single operation. This changes the complexity from O(n squared) to O(n).
When Prepending vs. Appending Matters
If you need the new rows at the top of the final result but are collecting data in a loop, it is more efficient to collect everything first and then control the order in a single pd.concat() call:
import pandas as pd
existing_df = pd.DataFrame({
'Name': ['Alice', 'Bob'],
'Age': [25, 30]
})
new_data = [
{'Name': 'Charlie', 'Age': 35},
{'Name': 'Diana', 'Age': 28}
]
new_rows_df = pd.DataFrame(new_data)
result = pd.concat([new_rows_df, existing_df], ignore_index=True)
print(result)Output:
Name Age
0 Charlie 35
1 Diana 28
2 Alice 25
3 Bob 30Quick Reference
| Goal | Method |
|---|---|
| Add single row to top | pd.concat([new_row_df, df], ignore_index=True) |
| Add multiple rows to top | pd.concat([new_rows_df, df], ignore_index=True) |
| Add row to bottom | pd.concat([df, new_row_df], ignore_index=True) |
| Build from many rows | Collect in a list, then pd.DataFrame(list) once |
- Use
pd.concat([new_row, df], ignore_index=True)to add rows at the top of a DataFrame. - Always set
ignore_index=Trueto maintain clean sequential indexing. - Avoid the removed
.append()method, and never usepd.concat()inside loops. - Instead, collect all your data in a Python list first, then create the DataFrame in a single operation for optimal performance.