If I remember correctly, not just the files themselves but the entire memory available to COM programs at run time was limited to 64k.
It's funny how engineers think those times are long gone whereas the demand for very compact systems with low energy footprint is still there. So mastering programming within kilobytes is still a thing, don't disregard it!
COM files were not limited to only 64k of accessible memory, but the difference was that upon loading COM file got one full preallocated 64kB segment that got used for all of data, code and stack, while MZ format files specified in their header how many paragraphs (segment register increments, ie. 16 byte blocks) they need for code and how many additional uninitialized paragraphs should follow that (minimum and maximum required).
In both cases programs were free to allocate additional memory from DOS, but by default EXE files were loaded in such way that this wasn't necessary and automatically got the largest continuous block of free memory allocated to them (in fact they got the highest addressed block of free memory, but in any sane state of DOS it was also the largest).
> upon loading COM file got one full preallocated 64kB segment
IIRC, COM files got all available memory up to the 640K boundary and if you wanted to load additional programs, you had to shrink the preallocated region first.
To be more specific, COM files were loaded into a single segment (64k) - this is where the limitation comes from.
At the time of DOS, memory access was unrestricted, so, in a basic form, one had direct access to the entire base memory (640k). DOS viruses for example frequently resided just below the top of it, and/or manipulated the interrupt descriptor table (located instead at the very beginning).
It's funny how engineers think those times are long gone whereas the demand for very compact systems with low energy footprint is still there. So mastering programming within kilobytes is still a thing, don't disregard it!