Skip to content

Python Pandas: How to Append a Dictionary as a Row to a Pandas DataFrame

Learn the modern ways to add dictionary data as rows to a Pandas DataFrame after the .append() deprecation, including .loc[] for single rows and pd.concat() for batch processing.

Adding rows from dictionaries is common when collecting data incrementally or processing records one at a time. With the deprecation of .append() in Pandas 2.0, modern alternatives provide better performance and clearer intent.

Assign dictionary values directly to a new index position:

import pandas as pd

df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})

new_row = {'Name': 'Charlie', 'Age': 35}

df.loc[len(df)] = new_row

print(df)

Output:

      Name  Age
0    Alice   25
1      Bob   30
2  Charlie   35

This modifies the DataFrame in place and is the fastest method for single-row additions.

With Non-Sequential Index

import pandas as pd

df = pd.DataFrame({'Name': ['Alice'], 'Age': [25]}, index=[100])

df.loc[len(df)] = {'Name': 'Bob', 'Age': 30}

print(df)

Output:

      Name  Age
100  Alice   25
1      Bob   30

Using pd.concat() - For Multiple Rows

When adding many rows, collect them first and concatenate once:

import pandas as pd

df = pd.DataFrame({'Name': ['Alice'], 'Age': [25]})

new_rows = [
    {'Name': 'Bob', 'Age': 30},
    {'Name': 'Charlie', 'Age': 35}
]

df = pd.concat([df, pd.DataFrame(new_rows)], ignore_index=True)

print(df)

Output:

      Name  Age
0    Alice   25
1      Bob   30
2  Charlie   35

Why Batch Processing Matters

import pandas as pd

df = pd.DataFrame({'A': []})
for i in range(1000):
    df = pd.concat([df, pd.DataFrame([{'A': i}])])  # Creates new DF each time

rows = [{'A': i} for i in range(1000)]
df = pd.DataFrame(rows)  # Single operation

Output:

       A
0      0
1      1
2      2
3      3
4      4
..   ...
995  995
996  996
997  997
998  998
999  999

Why .append() Was Deprecated

The old .append() method had several issues:

  • Performance: Created a full copy on every call
  • Confusion: Returned new DataFrame, didn't modify in place
  • Inconsistency: Different behavior from list .append()
df = df.append({'Name': 'Charlie', 'Age': 35}, ignore_index=True)

Handling Missing Columns

When dictionary keys don't match DataFrame columns:

import pandas as pd

df = pd.DataFrame({'Name': ['Alice'], 'Age': [25]})

new_row = {'Name': 'Bob', 'Age': 30, 'City': 'NYC'}

df.loc[len(df)] = new_row
print(df)  # City column not added

df = pd.DataFrame({'Name': ['Alice'], 'Age': [25]})
df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)
print(df)  # City column added with NaN for Alice

Output:

    Name  Age
0  Alice   25
1    Bob   30
    Name  Age City
0  Alice   25  NaN
1    Bob   30  NYC

Practical Example: Data Collection Loop

import pandas as pd

df = pd.DataFrame(columns=['Timestamp', 'Value', 'Status'])

collected_rows = []
for i in range(5):
    record = {
        'Timestamp': pd.Timestamp.now(),
        'Value': i * 10,
        'Status': 'OK' if i % 2 == 0 else 'Warning'
    }
    collected_rows.append(record)

df = pd.concat([df, pd.DataFrame(collected_rows)], ignore_index=True)
print(df)

Output:

                   Timestamp Value   Status
0 2026-02-16 21:56:43.674656     0       OK
1 2026-02-16 21:56:43.674905    10  Warning
2 2026-02-16 21:56:43.674910    20       OK
3 2026-02-16 21:56:43.674913    30  Warning
4 2026-02-16 21:56:43.674916    40       OK

Quick Reference

Method Best For Modifies Original
df.loc[len(df)] = dict Single row addition ✅ Yes
pd.concat([df, pd.DataFrame(rows)]) Multiple rows ❌ No (returns new)
Scenario Approach
One row at a time .loc[len(df)] = row_dict
Multiple rows at once pd.concat([df, pd.DataFrame(list_of_dicts)])
Loop with many iterations Collect in list, concat once at end

Summary

  • Use .loc[len(df)] = dict for adding single rows-it's fast and modifies in place.
  • Use pd.concat() when adding multiple rows, collecting all dictionaries first and concatenating once.
  • Avoid the deprecated .append() method, and never use concat() inside loops for performance reasons.
Navigation