Two pointers per node — next and prev — so the list reads both directions and edits at either end in constant time. The price is memory.
A doubly linked list gives every node a second pointer: prev, aimed at the node before it. With links running both ways, you can walk forward from the head or backward from the tail — and with a tail reference you can add or remove at either end in constant time, something a singly linked list can't do at the back. The price is memory and bookkeeping: two pointers per node, and every insert or delete has to keep both of them straight.
Each box is a node. The top arrow is its next pointer, the bottom arrow is prev. head and tail mark the ends, and both run into null.
Everything a singly list does at the front — plus the same speed at the back, and the ability to walk either way.
Both ends are now O(1) — the win over a singly linked list, paid for with an extra pointer per node.