Melt butter in a large pot over medium heat. Add onion and cook 4–5 minutes until soft but not browned.
Stir in garlic and cook 30 seconds, just until fragrant.
Sprinkle in flour and cook, stirring constantly, for 1 minute to remove raw flavor.
Slowly whisk in chicken broth until smooth. Whisk in milk and half-and-half.
Add broccoli, grated carrot, smoked paprika, nutmeg, Dijon (if using), and a pinch of salt and pepper.
Bring to a gentle simmer and cook 15–18 minutes, or until the broccoli is very tender and easily pierced with a fork.
Using an immersion blender, blend partially until thick and creamy, leaving some broccoli texture for a classic finish.
Reduce heat to low. Let the soup stop actively simmering. Gradually add cheddar and Gruyère in small handfuls, stirring constantly until fully melted. Do not boil after adding cheese.
Taste and adjust seasoning. Serve hot.