Boil pasta shells in a large pot of heavily salted water according to the directions on the box. Remove shells from heat and drain once al dente (just tender). Try not to overcook the shells because this will make them too mushy later.
Melt butter in a large, deep, heavy-bottomed pot or dutch oven over medium-high heat. Add onion and cook until onion becomes translucent, about 6-8 minutes, stirring occasionally. Add flour and stir to incorporate. Continue to cook over medium-high heat, stirring constantly, for another 2 minutes, or until thickened (this is what's called creating a "roux"). Add milk and heavy cream slowly into the roux, whisking constantly. Stir together until creamy and heated through. Add cheeses in small handfuls, taking care to stir until all the cheese is melted before adding more. Heat through. The sauce will look quite liquidy. Season with kosher salt and freshly ground black pepper to taste.
Add the pasta shells and stir well to coat. Heat through, stirring frequently. Serve while hot.