On Solana, programs are stateless. If your program needs to remember something per user, per game, per config, it needs a deterministic address it can find again later without storing that address anywhere. PDAs are that address.

I spent this week building a small Anchor counter program — nothing exotic, just enough surface area to run into the real questions: why does find_program_address need a program ID, why is the bump part of the seeds and not a separate thing bolted on afterward, and what actually happens when an account gets "closed." This post is me writing down the answers before they fade, aimed at whoever is where I was a week ago.

The mental model

The Web2 shorthand I kept reaching for was: a PDA is like a database primary key you can compute from the row's logical identity. If you know the user ID, you know the row. You never store the key anywhere separate from the thing that produces it.

That analogy gets you most of the way, with the database being the entire Solana account model, the key derivation being a hash, and the program ID baked into the hash so that only your program can ever sign for the result.