Full-stack projects are pretty daunting. If you’re just doing the front end, you have the structured data from the back end to work with. And if you’re just building the back end, you either have the front end letting you know what it needs. or if it’s not done yet, you can build the API to whatever structure you think is best.
But if you need to do both (and especially if you're a solo developer or indie hacker, and you don’t have a team providing design ideas or constraints), you’re free to go in any direction you like.
Which is good. But also pretty daunting.
So do you start with the front end, and use some dummy data or random values for the information you need from the not-yet-built back end? Or start with the back end, and imagine how the front end might send and use the data you provide?
Honestly, I've tried both. And my preference is to build the front end first.
But not ALL of the front end.
Just one feature at a time.
How I do things is a bit like this:
Feature 1
⬇️
Front-end
⬇️
Back-end
🔁
Feature 2
⬇️
Front-end
⬇️
Back-end
🔁
Feature 3
⬇️
Front-end
⬇️
Back-end
🔁
That's the basic outline for how I do full-stack development. But there's no right or wrong answer. You could build all the back-end first, or all the front-end first.
I find breaking the project down into small features and getting them finished one at a time makes everything a little less overwhelming (especially when starting a new project).
Let’s dive into a few more details.
Get the build working
The first thing I do when I start my project is get the build working. I'm usually on the MERN stack, so that would be:
- setting up Node.js & Express on the back-end
- setting up webpack for my React build
- setting up Express to serve my React app in development
You can start with the most simple setup. If you are not using a monorepo (where your front-end and back-end are together in the same repository), you can just go ahead and get your front-end development build working.
I've even started with a simple React boilerplate in Codepen. But if you are planning to build a full-stack app, you're just pushing off work you will need to do later anyway.
Start with the front end
Now we have our full-stack development build working, we are ready to start creating something.
And for that, I start on the front end.
I mean, you could argue that we already started with the build process, and that was kinda back-end work. And I'd agree with that. But we weren't building the full-stack application yet, we were just setting things up!
The first and only thing your future users will see is the front end (unless you are building an API - in which case you're reading the wrong blog post!).
And I find when I start with the front end, I put myself in the user's point of view. What do I want them to see? And what do I want them to experience?
If I build from the back-end first, I tend to think more from the developer's point of view. What data do I need, how should I structure it, and how do I validate it? And that's all very important. But not if nobody uses your service because the front end is too complex, messy, or technical for them!
So I start from the user's point of view - the front end.
Get that right, and we can handle all the server stuff afterwards.
But I don't build the full front-end application, I start with one single feature.
Build a feature on the front end
You could start with a login page, a payment form, or an account settings page. But that's all pretty generic.
I find it most exciting to start with the main feature of whatever I am building.
Let's say I'm building a to-do list app. I'd start with a to-do item. Or the form to add a new todo.
I start with the main feature for two reasons:
- It gets me excited about the project
- It might throw up a few problems that I need to solve
Because your main feature should be something different and unique. That's why you are building it!
And once you have figured out those unique pieces of the puzzle, everything else should be pretty straightforward!
Finish the feature on the back end
Now you have the feature - or at least one page or component of the feature - built on the front end, you can build the corresponding back endpoint for it.
For me, that's usually a server handler and API endpoint.
Going back to the to-do list app example, I'd add a route to GET
a to-do item (and list to-do items). And a POST
route to add a to-do item.
const express = require('express');
const router = express.Router();
// list all to-dos
router.get('/todos', getTodos);
// add a to-do
router.post('/todos', addTodo);
// get a to-do
router.get('/todos/:id', getTodo);
If you want to know more about how I structure my back-end, see a future-proof Node.js express file/folder structure and future-proof API versioning with Node.js & Express.
Now I have the routes, I can add the handlers and functions (getTodos
, getTodo
etc) to add todos to the database and fetch todos from the database.
And once that's working, I can wire it up to my already finished feature on the front end.
Wire the feature up
Now we need to connect the front-end to the back-end.
For me, I will usually connect the front end to the back end using an API request to send or fetch data from the API endpoint we just created on the server. It could also be a serverless function or a platform like Firebase.
This is the exciting part. Once we wire up the front-end and back-end, our one little feature can be used.
Because I have the back end working for this one small feature, I'll be able to remove any dummy data from the front end when I wire it up.
That means I'll be able to test it full stack (end-to-end) before moving on to the next piece of the puzzle.
And that's why I build one feature at a time.
It's really cool once you get one feature fully working before moving on to the next. And as you start using the features, you might spot issues or changes that will make them work even better, while the feature is still fresh in your mind.
So you can tweak it, and make sure you are happy(ish) with how it is working before moving on.
Repeat
Now we have a tiny part of our full-stack application working. The front-end is connected to the back-end, and we can use that feature.
All we need to do now is repeat that.
Build another feature, or the next part of the current feature, or the next page or component.
Repeat. Repeat. Repeat.
Until you're finished!
And that's the hard part - getting it finished.
I can't say I always finish every project I start, but building a feature at a time has certainly helped me get projects finished without getting bored or overwhelmed part way through.