In a large mixing bowl, combine ground beef, ground pork, breadcrumbs, Parmesan cheese, parsley, egg, garlic, Italian seasoning, salt, and pepper. Mix gently until just combined.
Shape mixture into small meatballs, about 1 inch in diameter, yielding around 20-24 meatballs.
Heat olive oil in a large skillet over medium heat. Add meatballs in batches and cook for 5-7 minutes, turning occasionally until browned on all sides. Remove and set aside.
In the same skillet, add diced onion, carrots, and celery. Saute for 5-7 minutes until softened and onion is translucent.
Add chicken broth and diced tomatoes with juices to the skillet. Stir to combine and scrape up browned bits from bottom.
Bring to a gentle boil, then reduce heat to low and simmer for 10 minutes.
Return browned meatballs to the pot. Pour in heavy cream and stir until well combined. Add red pepper flakes if desired.
Let soup simmer for 15-20 minutes, stirring occasionally, until meatballs are cooked through to internal temperature of 160°F.
Add chopped spinach and stir in, allowing it to wilt for 2-3 minutes.
Taste and adjust seasoning. Serve hot, garnished with fresh basil leaves.
Notes
Don’t overmix the meatball mixture as this can make them tough. Mix just until ingredients are combined.
Meatballs don’t need to be fully cooked when browning. They’ll finish cooking in the soup.
For a lighter version, substitute ground turkey for beef and pork, adding a tablespoon of olive oil to keep them moist.
Soup can be made ahead and refrigerated for up to 3 days. Flavors improve overnight.