This question comes up on almost every new project, and the honest answer is that neither option is universally correct. Auto-increment integers and UUIDs solve different problems, and picking the wrong one does not usually break anything on day one. It shows up later, once the assumptions baked into your schema stop matching how the system actually gets used.
An auto-increment integer is small, fast to index, and sorts naturally by insertion order, which makes pagination and ordering trivial. It is also easy to read and communicate: telling a colleague "check row 4821" is a lot friendlier than reading out a 36-character UUID over a call. For a single database instance where nothing else is generating ids independently, this is usually the simpler and faster choice.
The moment you have more than one system generating records independently, whether that is sharded databases, offline-first mobile clients creating records before they ever reach a server, or merging data from multiple sources, sequential integers collide. Two different clients can both create "record 1" before either has synced, and now you have a conflict to resolve. Sequential ids also leak information: an incrementing order id or user id tells anyone watching roughly how many records exist and how fast they are being created, which is sometimes a bigger problem than it sounds for a competitor or an attacker doing reconnaissance.
A random UUID (version 4) can be generated anywhere, by anyone, with no coordination and no meaningful chance of collision, even across billions of records. That makes it the right default for distributed systems, offline-capable clients, or any case where you want the id assigned the moment a record is created rather than waiting for a database round trip to hand one back. It also does not leak volume information the way a sequential id does.
UUIDs are 16 bytes versus 4 or 8 for an integer, which adds up across a large table and its indexes. Random UUIDs also insert in random order rather than sequentially, which can fragment certain database index structures over time and hurt write performance at scale. Some teams split the difference with a UUID variant that embeds a rough timestamp (UUIDv7 being the increasingly common choice for this), which keeps most of the distributed-generation benefit while restoring roughly sequential insert order. If you are not already hitting scale where index fragmentation is a measurable problem, this is a detail worth knowing but not worth optimizing for on day one.
If you are building something small, a single database, no offline clients, no distributed writers, an auto-increment integer is genuinely fine and often the pragmatic choice. Once any of those conditions stop being true, a random UUID is worth the extra storage cost. You can generate v4, v1, or v5 identifiers with the GUID Generator on this site to test either approach before committing your schema to one or the other.