Side Projects That Ship: Scoping, Finishing, and Launching Small Tools
Every developer has a graveyard. A ~/projects folder full of directories that represent the first three excited weekends of some idea, then silence. A half-built CLI tool. A database schema for the app that was going to replace Notion. A scraper that worked once. A game that got as far as a moving sprite.
This is universal and it’s not a character flaw. Side projects have a natural attractor state: stuck at 80%, not bad enough to delete, not finished enough to use. The graveyard grows.
What separates the projects that actually ship from the ones that don’t is rarely talent, time, or ideas. It’s a set of specific, learnable decisions made before and during the build. This guide covers those decisions.
The Single Most Important Reframe
Most developers think about side projects as things they build and then maybe ship. The mental model is: build → (optionally) ship.
The model that produces shipped projects is the reverse: ship → then keep building.
This sounds like a platitude until you actually sit with what it implies. If shipping is the goal from day one, every scope decision is filtered through “does this get me to something shippable, or does it delay it?” The answer restructures your entire build.
A notes app that ships on day 30 as a single-file web app with localStorage gets used, gets feedback, and either grows or gets abandoned with something learned. A notes app planned to eventually have real-time sync, plugins, a mobile app, and an AI assistant ships never.
The shipped version wins even if it’s embarrassing. The unshipped version wins nothing.
Scoping: The Skill Nobody Teaches
Scoping is the practice of deciding what a project is not. Most side projects fail in scoping — not because the developer can’t build, but because the scope keeps expanding to match the full vision before anything ships.
The Feature Triage
When you have an idea, write down everything it could do. All of it. Then go through the list with a brutal filter: which of these is required for the core value to exist?
Not “would be nice.” Not “users will want.” Required for the core value to exist.
For a CLI tool that generates boilerplate for new projects:
- Generates a basic file structure — required
- Reads a config file for preferences — required
- Supports 3 languages — maybe, but maybe 1 ships faster
- Has a TUI with colors and spinners — nice, not required
- Works as a VS Code extension too — not required
- Has a web UI — not required
- Syncs templates to the cloud — not required
- Supports team sharing — not required
Version 1.0 is the first bullet, possibly the second. Everything else is v1.1, v2.0, or never.
The question to ask every time a feature creeps in: “If this wasn’t there, would a real person still get value from using this?” If yes, it’s optional. Cut it.
The Smallest Useful Version
Define the Smallest Useful Version (SUV) before you write a line of code. This is not the smallest possible version — it’s the smallest version that genuinely solves the problem for at least one real person (including yourself).
Write it down explicitly:
SUV: A command-line tool that takes a URL and returns a summarized list of tasks extracted from the page. No login, no storage, no configuration. Input URL, get task list, exit.
Everything outside this definition is out of scope for v1. Not forever — just for v1. You will be tempted. The definition is the anchor.
Time-Boxing the Build
Pick a deadline before you start, not when you get stuck. The deadline should be slightly uncomfortable — long enough to build the SUV, short enough that scope creep has nowhere to hide.
For most weekend projects: 2–4 days of actual work. For most solo evening projects: 2–3 weeks of evenings. For more complex tools: 4–6 weeks maximum before a v0 ships to at least one person.
The deadline is not when the project is “done.” It’s when something ships. Done is a trap — software is never done.
Technology Choices for Shipping
The technology choice is where a lot of projects die. Developers use side projects as a chance to learn something new, which is great, but “learn new tech” and “ship something” are competing goals. When they’re both the goal, neither happens.
The Boring Technology Principle
Use the most boring technology that solves the problem. The goal of a side project that ships is to ship, not to evaluate Rust vs. Zig for CLI performance. That’s a different kind of project.
If you know Python, the CLI is Python. If you know Node, the web app is Express + vanilla JS. If you know Go, the server is Go. “Boring” here means “the thing you can build fastest with the tools you know best.”
The corollary: if learning a new technology is the actual goal of the project, that’s fine — but acknowledge it. Expect the project to take 3× longer and have half the chance of shipping. Not bad, just honest.
The Single-File Start
Starting with the simplest possible architecture — one file, no framework, no database — removes friction at the most vulnerable phase of a project: the beginning. A project that starts as a single Python script has a better chance of shipping than one that starts with a monorepo, a CI pipeline, and three services.
You can always refactor later. You can’t ship what you never built.
Single-file CLI (Python):
|
|
Single-file web app (Python + Flask):
|
|
This runs. You can show it to someone today. That’s the point.
When to Add Infrastructure
Add complexity when you can’t avoid it — not before:
| Problem you hit | What to add |
|---|---|
| Need to persist data | SQLite (not Postgres, not Redis) |
| Need user accounts | A single JWT secret + bcrypt |
| Need background jobs | A queue in SQLite + a worker loop |
| Need real-time updates | Server-sent events (SSE) |
| Need to deploy | A single VPS, a Dockerfile |
| Need a database in the cloud | Turso, PlanetScale, or Supabase free tier |
The pattern: use the simplest thing that solves the immediate problem. Upgrade only when you’re constrained.
The 80% Problem: Getting Unstuck
Almost every side project stalls at roughly 80% done. The exciting core is built, it works, and now there’s a list of things that need to happen before you can “really” ship: edge cases, polish, documentation, deployment setup, that one feature that feels essential.
This is the moment most projects die. Understanding why it happens is the first step to getting past it.
Why 80% Is a Trap
The 80% phase lacks the dopamine of the early build. The first 60% of a project is all new: new features, new problems, new things working for the first time. The last 20% before ship is slog: error handling, testing edge cases, writing a README, setting up a domain, packaging.
The mind drifts to new project ideas, which are all promise and no slog. The unfinished project represents past investment (sunk cost) plus future work (obligation). The new idea represents only future excitement.
The counterforce: don’t start the next project until the current one ships. This is a hard rule and worth keeping hard.
The Completion Checklist
When you feel stuck at 80%, make the path to done concrete. Write down every remaining task that stands between you and shipping. Not someday tasks — actual blockers. Then ask, for each one:
- Is this actually required for v1?
- If I cut this, would a real user still get value?
For anything that answers “no” to #1 or “yes” to #2: move it to a v1.1 list and remove it from the blocker list. You’ll often find that 80% is actually 95% when you’re honest about what’s actually required.
Then estimate the remaining tasks. Not in hours — in 2-hour blocks. If the remaining work is 4 two-hour blocks, you ship in two weekends. Having a concrete number changes “this might go on forever” to “I have 8 hours of work left.”
The Fake Ship
If you’re really stuck, deploy a fake version. Put up a landing page that describes what the tool will do. Share it with two people you know. Get their reaction.
This does something psychologically powerful: it makes the project real. It has a URL. Someone has seen it. The project exists in the world in a way that a local folder doesn’t. Suddenly finishing it feels different — there are people who know about it.
Shipping: What It Actually Means
“Ship” means different things at different stages. You don’t need a polished landing page, HackerNews post, and Product Hunt launch to have shipped something.
Tier 1: Shipped to Yourself
The project is deployed somewhere, running, and you use it. This is harder than it sounds and more valuable than it seems. A tool you actually use generates real feedback — you discover what’s missing, what’s annoying, what you reach for that isn’t there. Running in production (even if production is just your own laptop) changes how you think about the project.
Tier 2: Shipped to One Person
Share it with one person who isn’t you and who has the problem it solves. Watch them use it if you can. Listen to what confuses them. This is more valuable than any amount of internal testing.
Getting to Tier 2 doesn’t require a polished README, a domain name, or a launch. It requires a working thing and an email or Slack message.
Tier 3: Publicly Available
The project is on the internet, findable by strangers. This could be:
- A GitHub repo with a working README
- A CLI on PyPI or npm
- A web app at a real URL
- A VS Code extension in the marketplace
Tier 3 is where most developers aim when they say “ship,” but it’s actually Tier 3 on a ladder that starts at Tier 1. Get to Tier 1 first. Then Tier 2. Tier 3 follows naturally.
The README as Ship Requirement
Before Tier 3, write a README that includes:
- What the project does (one sentence)
- Who it’s for
- How to install it
- One working example
That’s it. No philosophy, no roadmap, no “contributions welcome” boilerplate. If a stranger can read those four things and run the example, you’re ready.
|
|
pip install quicksum
## Usage
quicksum https://example.com/some-long-article
Output:
• Update your nginx config to use HTTP/2 • Restart the service after making changes • Test with curl -I https://your-domain.com
That’s a shippable README.
After Shipping: What Next
Once something is publicly available, you face a fork: build more, or move on.
When to Keep Building
Keep building if:
- People are using it and asking for specific things
- You’re using it yourself and keep hitting limitations
- The core problem is bigger than your v1 addressed and you’re still interested in it
When you keep building, the same rules apply: scope each iteration, define what ships, time-box it.
When to Declare Victory and Move On
Move on if:
- Nobody is using it despite reasonable exposure
- You’ve lost genuine interest in the problem
- The v1 solved the problem well enough that there’s nothing worth adding
Declaring victory is underrated. A shipped, finished project — even a small one — is a real thing in the world. It taught you something. It solved a problem. It’s done.
The graveyard is for unshipped projects. Finished projects belong in a portfolio, a resume, a README you’re proud of, or a conversation you have with someone about what you’ve made.
A Pattern That Works
Here’s a concrete workflow that reliably produces shipped projects:
Day 0: Define Write three things down:
- The one-sentence description of what it does
- The Smallest Useful Version (SUV) — exactly what v1 does and does not do
- The ship deadline — a specific date
Days 1–N: Build the SUV Work only on what’s in the SUV definition. When a new idea occurs to you, write it in a “future” list and keep building. Stop adding until v1 ships.
N-2 days before deadline: Stop adding, start finishing Close the feature list. Everything from here is bug fixes, edge cases, and the README.
Deadline: Ship Deploy it, share it with at least one person, and write down what you learned.
One week later: Decide Is anyone using it? Are you using it? Does it have a future? Make the call: keep going, or declare it done and start the next thing.
Small Wins Compound
A developer who ships six small tools per year — a CLI, a script, a browser extension, a tiny web app — builds something the developer who never ships doesn’t: a pattern of completion. The shipped projects get easier because the muscle is developed. The scope decisions get faster. The “just get it out” tolerance for imperfection grows.
More concretely: six shipped projects per year is a portfolio. It’s demonstrated ability to take an idea from concept to something real. That’s rare, and it’s worth more in almost every professional context — interviews, freelance work, reputation — than any amount of in-progress work.
The goal isn’t to ship something perfect. It’s to ship something. Then ship another. That’s the whole game.
Comments