The Signal Component API: input, output, model, and queries In short: Once signals existed, the old decorators looked out of place. gave you a value that changed behind your back. gave you one that was empty until a specific moment. Signals make both problems impossible. The signal versions became final in v19. Inputs In the template you write instead of . In exchange you get three things. Required inputs are truly required. has the type — not "string or missing". No mark, no lying to the compiler. Angular checks that callers pass it. They fit together. An input is a signal, so it can feed a directly: mostly disappears. The reason to write it was nearly always "recalculate something when an input changes" — which is now a that reads the input. still exists and still works. You need it if you genuinely want the record of previous values, or if you mix old and new inputs. But the common case is gone. You can also rename an input, which reads better than the old way: Outputs Almost the same to use. Two real differences: is not an , which was always an odd choice because people occasionally subscribed to it directly and tied themselves to an internal detail. And listeners are cleaned up automatically. For an output that genuinely comes from a stream: Two-way binding with The old way was a pair — an input called and an output called — held together by a naming rule that nothing checked: works in the template exactly as before. A is one thing that sends changes upward, so the two halves cannot drift apart. exists too. Use only for genuine two-way binding — form fields, toggles, editable values. If the parent does not need to know about changes, a plain plus an is a clearer contract. Queries Three improvements worth naming. is gone. gives you a signal holding a plain array. No , no to subscribe to and clean up. It is a signal, so it works with like everything else. The timing problem is solved by design. The old rule was " is ready in , not ," and getting it wrong gave you nothing at run time. A query signal is empty until it is ready and then updates. So reading it early gives you a clear answer rather than a crash — and reading it inside a or means you are told the moment it becomes ready: is gone. That setting existed to say "get this ready earlier" and was a constant source of confusion. Query signals do not need it. The option survives for when you want something other than the default: The migration tools Three commands, all reliable: They rewrite the declarations, add at every place they are read including in templates, and skip anything they cannot change safely. What they skip, and why that is correct: Inputs the component writes to. values could be changed; signal inputs cannot. If a component assigns to its own input, the tool leaves it, because the fix is a design choice — usually if the parent should know, or a (next lesson) if it is local. Inputs read inside . Needs converting by hand. Queries using in ways that depend on the old timing. Run them one at a time, commit after each, and read the skipped list the tool prints. It is a genuinely useful list of the places where the old API was hiding a design question. Mixing old and new Fully supported. A component can have old and new inputs at the same time, in any combination. The one thing to know: only fires for old-style inputs. A signal input changing does not trigger it. If a component has both and relies on , that is the sharp edge — and exactly why the tool skips those cases. "But isn't input() just @Input() with brackets?" The brackets are the visible part. Three things underneath are genuinely different. 1. is typed as , not "T or missing." This sounds small and is not. The old pattern forced you to lie to the compiler: That switches off checking for the whole property. If the required setting is removed later, or the component is created another way, TypeScript stays quiet and you get a crash at run time. needs no mark, so nothing is switched off. 2. It is a signal, so other things can depend on it. An old input was a plain property — nothing could watch it. That is why existed. It was the only way to be told. Signal inputs feed directly, which is why most bodies simply vanish. 3. Inputs cannot be written to, and that catches real bugs. Old inputs could be changed by the component itself — creating a value that looks like it came from the parent but did not, and quietly reverting the next time the parent updates. The related myth: "signals killed lifecycle methods." Mostly, with real exceptions: Method Status --- --- Gone — that is Mostly gone — field declarations and resources cover it Gone — query signals sort themselves out Still useful — or Still needed — measuring the page, browser-only code The architect's view The clearest place to see the difference is a component wrapping an outside library — the single most common place piles up. The old shape. Six inputs, and a method that has to work out what changed and what to do about it: That b…