I came up with the idea on a Wednesday evening, exhausted after a long day of debugging internal dashboards. What if I built and shipped a real, working, full-stack application in 30 days without quitting my job? No weekends off, no excuses. Just a strict calendar and whatever energy I had left after 5 p.m. I had read about indie hackers pulling this off and secretly assumed they were either lying or single with no responsibilities. I have a partner, a dog that demands evening walks, and a job that occasionally spills into the night. Still, I wanted to know if it was possible for someone like me. So I set the rules: 30 calendar days, one fully functional web app with a backend, database, and deployed frontend, all built during the margins around a 40-hour workweek. This is what happened, what broke, and the three things I would absolutely do differently.
Picking a Project That Could Actually Be Finished
The first trap was project ambition. My brain immediately suggested a collaborative design tool or a real-time multiplayer trivia game. I had to physically stop myself. I settled on something far smaller: a personal book tracking app called Shelf. You could search for books by title, add them to a personal shelf with a status like “Want to Read” or “Finished,” and leave a private note. No social features. No recommendation engine. Just a clean, personal inventory with a searchable book database.
For the tech stack I chose React for the frontend, Node.js with Express on the backend, and MongoDB as the database. I picked MongoDB because the book data schema was flexible and I didn’t want to spend time designing relational tables. For the book search I planned to use the Open Library API, a free and open source book catalog that saved me from building my own. Authentication would be handled by Auth0’s free tier so I wouldn’t have to roll my own password hashing. The entire stack was chosen for speed, not elegance. I would deploy the frontend on Vercel and the backend on a single DigitalOcean droplet, the same $10 one I already had from a previous experiment.
Week 1: The Excitement Phase
The first week felt magical. I woke up at 5:30 a.m., coded for 90 minutes before work, then grabbed another hour in the evening after dinner. By Sunday night I had a working Express server, a MongoDB Atlas cluster, and a React app that could display a hardcoded list of books. The Open Library API integration was the first real hurdle. The search endpoint returned a sprawling JSON response with multiple editions of each book, and I had to deduplicate results by title and author. I wrote a small utility function that grouped results by a combination of title and first author name, and that got me close enough.
My job during the day started feeling like an interruption, which was both motivating and dangerous. I found myself drifting during a sprint planning meeting, mentally sketching React components. I knew I couldn’t sustain that, so I made a rule: no thinking about Shelf between 9 and 5. I failed that rule immediately. By Friday I had caught myself writing a useEffect cleanup function on a sticky note while waiting for a build to finish. I told myself it was fine. It wasn’t.
Week 2: The Mid-Project Wall
Week two was when the romance evaporated. I had to implement the actual shelf logic: adding a book, updating its status, deleting it. This meant building a proper API with authentication middleware, user-specific routes, and error handling that didn’t crash the server when someone sent an invalid book ID. I also had to connect the React frontend to these routes and manage loading states and empty states. None of it was hard conceptually, but it was a mountain of tedious wiring.
I got sloppy. I skipped writing tests entirely because they felt like a luxury I didn’t have time for. I hardcoded the user ID extraction in a way that broke when I switched from my local environment to the deployed version. One night I spent two hours chasing a bug where books would appear on the wrong user’s shelf, only to discover I had forgotten to scope the MongoDB query to the authenticated user. That was a rookie mistake. I was coding tired, making dumb errors, and then spending the next morning’s session fixing them. Progress slowed to a crawl.
My relationship also took a hit. My partner was supportive but visibly annoyed that I kept disappearing after dinner. I missed a Friday movie night we had planned. I apologized, but I could feel the resentment building on both sides. I realized I had not thought about the human cost of this challenge at all. I was so focused on the technical timeline that I forgot I share a life with another person. That was the lowest point.
Week 3: The Pivot and the Feature Cut
By the start of week three I had a working but ugly application. The core features functioned: you could log in, search for a book, add it, move it between shelves, and delete it. But the UI looked like a developer’s first Bootstrap prototype. No polish, no thoughtful spacing, no mobile responsiveness. I had also planned to add a notes feature where users could write private reflections on each book, but I was behind schedule and that feature would require another database model and a rich text editor component.
I made the hardest decision of the project: I cut the notes feature. I told myself I would add it after the 30 days if the app actually worked. This felt like failure, but in hindsight it was the only reason I shipped anything at all. I redirected the freed hours into making the core experience solid. I spent an evening learning just enough Tailwind CSS to clean up the interface. I added proper error messages, loading spinners, and a basic mobile layout. It wasn’t beautiful, but it stopped looking broken. I also bought a domain, shelfapp.io, and pointed it to the Vercel deployment. Seeing the app at a real URL, even in its incomplete state, gave me a jolt of motivation that carried me through the final push.
Week 4: The Final Sprint
The last week was a blur of deployment fixes, edge case handling, and a single terrifying security scare. I had initially stored user email addresses in local storage as a quick way to personalize the header. A friend who tested the app pointed out that this was a bad idea, not just for security but because the email wasn’t verified after login. I switched to fetching a minimal user profile from Auth0’s token instead. It was a small change but it reminded me that fatigue makes you take shortcuts you would normally never consider.
I also ran into a DNS propagation issue that made the site inaccessible for about four hours. I had never configured a custom domain on Vercel before, and I missed a CNAME record step. I panicked, thought I had lost everything, and then calmed down enough to read the documentation. It resolved itself eventually, but I lost an evening to a problem that had nothing to do with my code. Infrastructure work is humbling in that way.
On day 30, I sat down with my partner and showed her the finished application. She logged in, searched for a novel she had been meaning to read, added it to her “Want to Read” shelf, and said, “This is actually useful.” I exhaled. I had built a real, working, deployed full-stack app in 30 days while holding down a full-time job. It was not a startup. It was not going to make money. But it existed, and that existence mattered more than I expected.
What I Learned (And What I’d Do Differently)
The experience taught me three things that I will carry into every side project I ever attempt again.
Cut features brutally and early. The notes feature I dropped in week three was the right call, but I should have cut it in week one. I spent too many evening hours half-building something that never shipped. If a feature is not essential to the core experience, delete it from the plan before you write a single line of code. Your project’s survival depends on finishing, not on being feature complete.
Protect your relationships as aggressively as your code. I damaged trust with my partner during those 30 days, and that damage took weeks to repair. If I were doing it again, I would block off at least two weeknights as completely work-free, no exceptions. The project would take a few extra days, but no side project is worth straining the people who make your life worth living. I would also communicate the timeline clearly upfront and ask for feedback, rather than unilaterally disappearing into my office.
Timebox infrastructure work. I lost multiple evenings to deployment quirks, DNS misconfigurations, and tooling rabbit holes. In the future I will set a hard cap: no more than two hours total on deployment and infrastructure for a project this size. If my app can’t be deployed in an evening, I’m using the wrong stack or overcomplicating things. The goal is to get a real URL as early as possible, even with a messy codebase. You can clean it up later. You can’t get lost evenings back.
The Aftermath
Shelf still exists. I haven’t promoted it anywhere. About a dozen friends use it to track their reading, and I still add features occasionally when I have a free weekend. A few months after the challenge, I added that notes feature I had originally cut. It took a single afternoon, because the codebase was clean and I wasn’t sleep deprived. The app has remained stable with zero maintenance beyond occasional dependency updates.
More valuable than the app itself is the proof it gave me. I now know that I can build and ship a real software product in a month without sacrificing my job. The constraints forced clarity. I could not afford to overthink architecture. I could not spend three days choosing a component library. The deadline stripped away every form of procrastination, and what remained was a focused, sometimes painful, ultimately satisfying process.
If you have a 9-to-5 and a side project idea that keeps you up at night, I recommend setting a public, non-negotiable deadline. Tell someone. Ship something ugly. You’ll learn more from 30 days of focused, imperfect execution than from a year of idle planning. Just remember to warn the people you live with first.
