Preheat & prep
Preheat your oven to 375°F (190°C). Spray a 9-inch square baking dish with cooking spray. Peel (or scrub) and slice the potatoes into 1/8-inch rounds, then slice the onion thinly. Arrange potatoes in the prepared dish in three or four rows, leaving a little space so the slices sit slightly slanted. Tuck onion slices between and on top of the potatoes wherever they fit.
Make the cheese sauce
Melt 3 tbsp butter in a medium pot over medium heat. Whisk in ¼ cup flour and cook while whisking for about 30 seconds so the raw flour taste disappears. Slowly stream in 1½ cups milk, whisking constantly to avoid lumps. Raise the heat to medium-high and bring the mixture to a boil, then reduce to medium-low and simmer until the sauce thickens to a creamy gravy, about 5 minutes. Reduce heat to low and stir in 8 oz sharp Cheddar, ¾ tsp kosher salt, ½ tsp garlic powder, and a few grinds of pepper. Taste and adjust salt and pepper if needed.
Assemble & bake (first stage)
Pour the sauce evenly over the arranged potatoes and onions. Cover the pan tightly with foil and bake 45 minutes. This steam-phase softens the potatoes and lets the flavors meld.
Top & finish baking
Remove the foil and sprinkle Gruyère and Parmesan evenly over the top. Return the dish to the oven and bake, uncovered, until the potatoes pierce easily with a fork and the top turns golden brown, 30–45 minutes. For a super-crispy finish, switch the oven to broil for 1–2 minutes — watch closely so it doesn’t burn.
Rest & serve
Allow the gratin to cool 10 minutes so it sets slightly. Garnish with chopped chives or parsley and serve warm.