This question isn't asked often, but it's still relevant, so it's worth understanding the main differences:
Scope
var has function scope, so if we declare a var variable inside a {} block, it is still visible throughout the function where it was declared, or in the global object's scope.
Hoisting
In general, both var and let are hoisted to the top of their scope, but there is a significant difference when you try to access them.
var is hoisted and initialized with the value undefined, which is what we get when we access it. let is hoisted too, but trying to access it before the declaration throws an error.
Redeclaration
var can be redeclared within the same scope.
let cannot be redeclared within the same block, because it results in an error.