The fundamental thing is “edge matching”. When you lay two tiles next to each other, the edges of them need to join together as though they were drawn as one contiguous piece. Any features that get “cut in half” when they cross the edge need to continue without skipping a beat, on the next tile.
The most basic way I do this is that I start out by drawing without any regard to where the tile edge is going to be - I draw right across it. Everything done like this continues smoothly across the edge. I’ll draw a basic block of tiles, and choose not to care in the initial drawing - the result isn’t going to tile nicely at all - however, I have to start somewhere, and I can graft pieces of this initial drawing into other places to make it tile nicely later.
Many edges in a tile configuration need to match more than one tile. If you take a really basic tile configuration, where you have 1 interior tile, 4 border tiles, 4 “convex corner” tiles, and 4 “concave corner” tiles, an example would be the upper border tile - it needs to match not just copies of itself, but also needs to match nicely with the two upper convex corners, and the two lower concave corners. That’s 5 tiles right there that all need to match.
So the easiest and most straightforward way to guarantee these “matching edges” all fit with each other is for them to literally have exactly the same pixels. I take another tile that has that same edge (if I’m starting from scratch, this would e.g. be that initial drawing I talked about above. I take that tile, and I select about 4-6 pixels in from the edge, and just copy-paste that into my new tile. If you do this, you’ll get basic pixel-art tiles that seam decently - like any professionally-competent snes/genesis game. You’ll share a subsequent problem many of them never beat (only a scant few of the very best SNES games licked this problem), which is that the grid of your tiles will be rather obvious (because the stuff you copied will be exactly the same on every tile, and will repeat all over the place). You won’t have seams cutting across your tiles, but you will have texture that repeats every 16 pixels (or whatever your tile width is).
So how do you fight this? A pro trick is that you don’t have to have a carbon copy on every tile that shares a given edge - instead, any “lines” that cross the edge simply need to continue smoothly - at the very edge, they all have to start the same way, but past that, they can curl off in any direction. Likewise - it is lines, and bold features that most badly need to match - less striking things like the background fill texture can be much more different. For example, if you’re doing a brick texture, the mortar gaps between the bricks absolutely must match up - you can’t have one just “stop” suddenly. But the texture on the face of the brick - if it’s subtle enough, you might not have to copy that at all.
Naturally, the more and more tiles you have that match a given edge, the more trouble you’re going to have keeping seams from showing up if the appearance on them is actually different. So you’re fighting two contradictory things - you want more and more tile variations because that fights the grid, but you want less and less tile variations because the more you have, the harder it is to keep them from seaming. There’s no magic solution for resolving this.
One helpful thing is to have a low color count - the lower your color count, the more chance that stuff across an edge might match “by accident”. It’s one huge advantage of pixel art - with a very low color count, things across an edge might be exactly the same, even if you hadn’t intended them to be.