I've known about the ability of NDSolve[] to handle vector forms of ODEs for years. But the OP concerns a different form.
{
(* undocumented form *)
sol1 = NDSolveValue[{
ode1 = y'[t] == -{1, 2, 3}*y[t],
ic = y[0] == {1, 2, 3}},
y, {t, 0, 1}] // ListLinePlot,
(* documented form *)
sol2 = NDSolveValue[{
ode2 = y'[t] == -DiagonalMatrix[{1, 2, 3}] . y[t],
ic},
y, {t, 0, 1}] // ListLinePlot} // GraphicsRow

They're equivalent -- no doubt. Indeed, @azerbajdzan shows they're the same -- not surprising. This all seems obvious from the description in the OP of NDSolve[] setting up a diagonal system from an IVP like {ode1, ic}.
Here's what's different: The solution sol1 is not a solution to the equation ode1, but both sol1 and sol2 are solutions of ode2:
ode1 /. t -> 0 /. y -> sol1
ode2 /. t -> 0 /. y -> sol1
ode2 /. t -> 0 /. y -> sol2
(*
{-1., -4., -9.} == {{-1., -2., -3.}, {-2., -4., -6.}, {-3., -6., -9.}}
True
True
*)
Why is that? Well look at ode1, which is the actual input to NDSolveValue[]:
ode1
(* y'[t] == {-y[t], -2 y[t], -3 y[t]} *)
If you plug a vector such as y[0.] == {1.,2.,3.} in for y[t], you get a matrix on the right-hand side. As can be seen previous code output, if y is a vector-valued function, so is y'; and further, the left-hand side of ode1 will be a vector and the right-hand side will be a matrix. There is no way to satisfy ode1.
This problem of Plus[] and Times[] threading vectors and matrices in setting up vector/matrix forms of ODEs has a long history on this site, to which I've contributed many answers. (The threading is due to Plus[] and Times[] being Listable.) Long-time community members interested in differential-equations will know that often the solution has required the construction of ?NumericQ-protect functions to prevent threading. The issue in ode1 is the premature threading in {1,2,3} y[t]. The Times-threading does not occur after y[t] has a vector value as @azerbajdzan seems to think, but before it. In times past, this has yielded an error, with which site visitors have sought help. Indeed, DSolve[{ode1, ic}, y, t] still gives an error, which seems correct since ode1 cannot have a solution.
So if the input with -{1, 2, 3}*y[t] doesn't make sense, unlike the DiagonalMatrix[] form, what is NDSolve[] doing? It is easy to see, if you know the inner workings of NDSolve[] as explained in Advanced Numerical Differential Equation Solving in the Wolfram Language and other NDSolve[] manuals. NDSolve[] is un-threading the right-hand side of the ODE. It is somewhat remarkable, since threading is not strictly invertible. It is also worth remarking, though less remarkable, that it has bugs.
The unthreading converts ode1 to a diagonal system as explained in the OP, although it need not be a linear one as is the simple example in the OP. Consequently, it is equivalent to the explicitly diagonal system in ode2.
For instance, the first example gives the sort of error I'd expect, but the second, which changes a coefficient 3 to a 2, works fine:
NDSolve[{y'[t] == {2 t y[t] - y[t]^3/5, 3 t y[t] + y[t]^2/4},
y[0] == {2, 1}}, y, {t, 0, 1}]
NDSolve::ndfdmc: Computed derivatives do not have dimensionality consistent with the initial conditions.
NDSolve[{y'[t] == {2 t y[t] - y[t]^3/5, 2 t y[t] + y[t]^2/4},
y[0] == {2, 1}}, y, {t, 0, 1}]
(* {{y -> InterpolatingFunction[{{0., 1.}}, "<>"]}} *)
The problem seems to go away because of identical terms 2 t y[t] in both components in the second example. Bugs sometimes don't make a lot of sense.
Here is a way to inspect the unthreading:
ones // ClearAll;
ones[a_] := ConstantArray[1, Dimensions@a];
checkRHSFN // ClearAll;
checkRHSFN[rhss_, ics_ : 1] := Module[{state, ode},
{state} = NDSolve`ProcessEquations[{
ode = y'[t] == (rhss /. {y[t] -> y[t], y -> y[t]})
, y[0] == Replace[ics, n_?NumericQ :> n*ones[rhss]]}
, y, {t, 0, 1}];
Grid[
Join[
{{"ODE", ode}},
{#, state["NumericalFunction"]@#} & /@ {"FunctionExpression",
"ArgumentDimensions", "ResultDimensions"}
], Alignment -> Left, Spacings -> {1, Automatic}]
];
The right-hand side rhss in checkRHSFN[] can be given without the [t] arguments to y.
Two of the examples we've seen show that NDSolve[] does some work to get the job done. The NumericalFunction's "FunctionExpression" represents the right-hand side of the ODE. It is, in effect, evaluated on numeric quantities of the dimensions shown. This means that the threading happens after the y argument is given a vector value.
checkRHSFN[-{y, 2 y, 3 y}, {1, 2, 3}]
checkRHSFN[{2 t y - y^3/5, 2 t y + y^2/4}, {2, 1}]

Here's an example where NDSolve[] fails. The unthreaded expression in the function should be something like t y + {-1, -2, -3} y instead of just t y, and the solutions should decrease (right) instead of increase (left).
checkRHSFN[{t y - y, t y - 2 y, t y - 3 y}, {2, 1, 1/2}]


I'm pretty sure that this example and several others like it are bugs in the unthreading process, but I was wondering whether the proper behavior was documented. Maybe there is some reason why they should be dismissed.
NDSolveValueunder "Details and Options": "The c0, dc0, etc. can be lists, specifying that u[x] is a function with vector or general list values." Then under "Scope - Ordinary Differential Equations" third example is "Solve for a vector-valued function:", where we can see even more complicated example of such usage. $\endgroup$NDSolve[]andDSolve[]solve matrix-vector forms of ODEs and have given many answers using such. And I already knew that the above form is equivalent to the corresponding diagonal matrix form with vector solution (duh). But the above is different from the documented form. $\endgroup$NDSolveValuereally solving is the form shown in azerbajdzan's answer. It is more a bug ofNDSolveValuethen a feature to me. On the other hand if nonsensical input is provided should we be expecting any reasonable output? $\endgroup$NonThreadableisn't introduced until v14.1. $\endgroup$NDSolve[{y'[t] == -{1, 0, 3}*y[t], y[0] == {1, 2, 3}}, y, {t, 0, 1}]emits an error and returns unevaluated. $\endgroup$