Yep. The very simplest solution is called a shift register. You can use them for both input and output -- though generally each chip is dedicated to one or the other. Well, that is to say, they're either "serial to parallel" or "parallel to serial".
Say you have an 8-bit parallel-to-serial shift register, it'll have 8 parallel input lines, and when you read the serial line, it'll give you the value of each of its 8 parallel input pins in sequence. Or for output, the other way around (writing 8 bits to one line sets the output on all 8 parallel output pins). Usually you can chain them together, so that reading/writing beyond those 8 bits shifts in the values from the next register you've connected.
But if you have a LOT of inputs, like building in a keyboard, then it makes sense to do the multiplexing arrangement others have mentioned. That way with N GPIOs you can read N2 inputs. In addition to the advice here, you should find plenty of tutorials online since DIY keyboards are a thing.
Still, since shift registers are so cheap (I've seen them at 50 for $1), sometimes it's just all a matter of managing complexity in whatever way makes the most sense for you at the time.