Any multi-stage rocket design has to obey three rules to achieve good performance:
- Fuel type and engine design must allow for a high specific impulse. This is equally valid for single and multi staged rockets.
- Each stage's payload (which can be another stage) should outweigh the stage's structure, otherwise most of the energy is wasted accelerating the structure.
- Total weight should decrease rapidly with each stage separation, so that the lower stage's heavy engines and interstage don't need to be duplicated.
A rocket with too few stages pushes a lot of empty tankage around and eventually violates rule #2. A rocket with too many stages and too little ∆v per stage has lots of duplicated engines and interstages and violates rule #3. Somewhere in between there's an optimum.
To design such a rocket, start with a given specific impulse and structural mass fraction. Distribute the remaining mass between fuel and payload and calculate ∆v per stage. Finally, calculate the number of stages to achieve the desired total ∆v. The tricky part is to chose the optimal fuel and payload fractions and to measure efficiency of the design.
To help that, I created the below plot. It shows mass efficiency (system specific impulse) over ∆v per stage for different structural mass fractions. Everything is normalized with respect to specific impulse of the fuel.

Example usage:
Your fuel's specific impulse is 3000m/s, you want a system specific impulse no less than 2500m/s to keep launch mass low and you can achieve a structural mass ratio of 4%. You look up 2500m/s (83.3% of 3000, y-axis) on the 4%-line, the result of which is a ∆v of 6600m/s (220% of 3000, x-axis) per stage.
6600m/s per stage allows a two-stage-to-orbit vehicle. More stages yield diminishing returns, as maximum efficiency of the 4%-line never goes above 90%. If you use too many stages with little ∆v per stage, efficiency will even drop.
I created the plot using Matlab/Octave as follows:
p = [0.02, 0.04, 0.07, 0.10, 0.15, 0.20, 0.30, 0.40]; # structural mass ratio
v1 = (0.0:0.01:4)'; # v_end / I_sp
ma = 1.0 ./ exp(v1); # non-fuel mass ratio
na = ma - p; # payload mass ratio
na(na < 0) = 0;
v2 = v1 ./ log(1.0 ./ na); # I_ssp / I_sp
h = plot(v1, v2, 'LineWidth', 3);
set(gca, 'fontsize', 16)
axis([v1(1),v1(end),0,1]);
grid minor
h = legend(arrayfun(@(x)[num2str(x*100),'%'], p, 'UniformOutput', 0));
set(h, 'FontSize', 16);
ylabel('Issp / Isp');
xlabel('∆v / Isp');