Most Terraform advice is really "here's the mistake that caused a real problem, and the habit that would have prevented it." These are ranked roughly by how much damage the mistake causes, worst first.
Not even to fix something quickly. terraform state has real subcommands for the operations people are tempted to do by hand (state mv, state rm, import) that update state consistently instead of leaving it slightly wrong in a way that only shows up on the next plan, often as "destroy and recreate" on something that was actually fine.
Local state works right up until it doesn't: two people apply within a minute of each other, or a laptop dies with the only copy of state on it. A remote backend (S3+DynamoDB, GCS, Terraform Cloud, etc.) with locking turns "corrupted state, reconstruct it by hand" into "the second apply just waits for the first one to finish." This is cheap to set up correctly at the start and expensive to migrate to later once real infrastructure already exists without it.
An unpinned provider means the exact same configuration can behave differently on two different days, on two different machines, for no reason visible in a diff. Pin with a constraint (~> 4.52), commit the generated .terraform.lock.hcl, and a plan run six months from now uses the same provider build as the one run today.
A hardcoded secret in a .tf file is the obvious mistake; the less obvious one is that plenty of resource attributes containing secrets end up written into the state file in plain text regardless of where the value came from, since state has to record the real value to know if it's drifted. Treat state as sensitive: encrypt it at rest (most remote backends do this by default), restrict who can read it, and prefer resources/providers that support write-only or ephemeral values where the underlying API allows it, so the secret is used without ever being persisted to state at all.
A single 3,000-line main.tf is technically valid and practically unmaintainable. A module that does one coherent thing, with a small number of well-named inputs and outputs, can be reasoned about, tested, and reused. The test that actually matters: could someone else read this module's variables and outputs and understand what it does without reading the resource blocks inside it?
"It applied without an error" and "it did what I expected" are different claims. A plan that says -/+ (destroy and recreate) where you expected ~ (update in place) is Terraform telling you a change you thought was minor actually forces replacement — worth knowing before it deletes something with real data on it, not after.
Resource names, variable names, and tags that follow one obvious pattern make a codebase searchable and a diff readable at a glance. Whatever the pattern is matters less than that there is one and it's followed — the cost of inconsistency compounds every time someone has to guess which of three naming styles a new resource should follow.