Start the onions, and don’t rush them. Melt the butter with the olive oil in a large pot over medium heat. Add the sliced onions and the ½ teaspoon salt, stirring to coat. Cook, stirring occasionally, for 35 to 40 minutes, until the onions are a deep golden-brown, jammy, and significantly reduced in volume. This is the step most versions of this dish shortcut, and it’s the reason they end up tasting thin: real caramelization is a slow breakdown of the onion’s natural sugars, and it simply can’t be rushed by turning up the heat doing so just browns the outside while the inside stays raw and sharp-tasting. If the onions start sticking or browning too fast, lower the heat and add a splash of water to loosen the pan instead of speeding through it.
Add the garlic and flour. Once the onions are deeply caramelized, stir in the garlic and cook for 30 seconds until fragrant. Sprinkle in the flour and stir constantly for about 1 minute, until it’s fully absorbed and no longer looks raw or powdery.
Build the broth. Gradually pour in the beef broth, stirring constantly to work out any lumps from the flour. Add the Worcestershire sauce and thyme, then bring to a simmer and cook for 5 minutes, until slightly thickened.
Cook the pasta separately. While the broth simmers, cook the pasta in salted boiling water until just shy of al dente about 2 minutes less than the package directs, since it’ll finish cooking in the oven. Drain and set aside.
Combine and season. Preheat the oven to 400°F. Stir the drained pasta into the onion broth mixture along with half the Gruyère. Taste and season with salt and pepper as needed. Pro tip: taste it here before it goes in the oven baking will concentrate the flavors further, so it’s easier to catch an under-seasoned batch now than after it’s baked.
Transfer and top. Pour the pasta mixture into a greased 9×13-inch baking dish and spread evenly. Top with the remaining Gruyère and the parmesan.
Bake. Bake for 15–18 minutes, until the cheese is fully melted and the edges are bubbling. For a deeply golden, slightly blistered top like a true French onion soup finish, switch to broil for the last 1–2 minutes, watching closely so it doesn’t burn.
Serve. Let the dish rest for 5 minutes before serving, since the sauce continues to thicken slightly as it cools.