Instead of storing all the zeros (non-existing edges), you only store the edges that exist. For every node , you keep a list of its neighbors.
Think of it like a contact list on your phone. You do not have an entry for every person in the world with "not a contact" next to them. You only store the people you know. The adjacency list works the same way.
For sparse graphs where is much smaller than , this saves massive amounts of memory. Most real-world graphs are sparse, so the adjacency list is your default choice.