I have never learned Docker.
Not "I know the basics and should go deeper". I mean I have never really used it. And the honest reason is that I never worked on anything that forced me to. For a long time, shipping a mediumish Next.js project end to end was itself the achievement. That was the ceiling I was working against, and Docker sat somewhere above it in a category of things I told myself I would get to later.
Later kept moving.
What Building the Company Project Actually Taught Me
The last few months have been the company project. It keeps growing, and I keep building on it, and somewhere in there I noticed something I did not like. I am still learning. The curve is still going up. But the slope is not what it used to be. It is increasing at a lower rate, and internally I am not satisfied with that.
Take the most recent thing I built. We needed a rate comparison system across lanes and weight slabs. The problem is that every vendor API only answers one question at a time. One lane, one weight, one configuration, one response. That is fine if a person is looking up a single shipment. It is useless if you want to compare anything properly.
So the data had to live with us. I built a pipeline that runs every fifth night in the background, walks through the set of countries and weight slabs, hits the vendor APIs for each combination, and writes everything into the database against service type and the rest of the metrics. It takes an hour or two to finish. Once it is done I can run whatever analysis I want on top of it, or export the whole thing to Excel and hand it over as a rate card.
Making those Excel files used to be a genuinely painful job. Now ninety five percent of it is handled, and the numbers are as accurate as what the vendors return.
That is a good outcome. I am happy with it. But look at what I actually learned from it: Prisma has transaction timeouts. That is it. That is the takeaway.

The Vercel Timeout, One Year Ago
The comparison is what bothers me.
About a year back I ran into Vercel's function timeouts for the first time, and that was a real wall. I had no idea what to do with a job that simply could not finish inside a request. That one problem is what pushed me to find Inngest, and Inngest went on to become one of the load bearing pieces of the whole project. Background jobs, email pipelines, PDF generation, Excel generation, and now these data fetching runs. All of it goes through Inngest. It is genuinely a great product.
That was learning that changed how I build things.
Prisma timeouts, by comparison, were a Tuesday.
Picking the Thing I Have Been Avoiding
So I decided to go after Docker. Not because a task demanded it this week, but because I can see where the company project is heading, and I would rather have the skill before I need it than scramble for it during an incident.
What I want out of it is unglamorous. Concepts first. Writing a Dockerfile. What the flags actually do, including the -it I have copy pasted a hundred times without thinking. Running Postgres and Redis as containers, putting them on a network, and understanding what a bridge is instead of nodding along when someone says it.
Then came the question of how to learn it. Option one was to pull a few images, run them, watch them start, and feel good about myself. Option two was to build something that would break if I got any of it wrong.

Why a To-Do App, of All Things
I am building a plain Express backend. The domain is a to-do app.
I know. A to-do app is the single most beaten project on the internet, and putting one in a portfolio is close to a joke at this point. But I picked it deliberately. The business logic is free. Nobody has to explain to me what a task or a due date is, and I will not lose fifty percent of my time debugging domain rules that have nothing to do with what I am trying to learn.
Because the interesting constraint is not the features. It is this: what happens to this thing at ten thousand concurrent users? At one lakh?
Scaling is the thing I think about day and night anyway. If the company product grows the way I think it can, that question stops being hypothetical. So I would rather ask it now, on a codebase where the answer is not tangled up with invoices and vendors and rate slabs.
The list of things I want in place, roughly:
- Rate limiting that actually holds under a burst
- Queues, with retries and a sane failure path
- Read paths that stay fast when the table is not small anymore
- Caching, and knowing what to cache instead of caching everything
- Sharding, eventually, if I get far enough to need it
- Every service running in Docker. Postgres, Redis, whatever else shows up.
I Do Not Know How to Do Most of This
Worth saying plainly: I have not built many traditional Express backends. This is my first properly complex one, complex meaning the scaling side, not the features. Right now the project is initialized and that is all. I have not designed the scaling strategy, and I genuinely do not know what will fall over first at that kind of load.
I might not pull it off. That is fine. The failure mode here is that I learn where my ceiling is, which is still more than I would get from running docker run postgres and calling it a day.
The Drizzle Experiment
One more thing I am folding in. I am using Drizzle instead of Prisma.
I was a Prisma fanboy. I still like it. The developer experience is excellent and Drizzle's, to me, is not close. I used to think the speed talk was overblown, that the difference could not possibly matter for what I build.
Then I spent months in the company project feeling latency that I could not fully explain. It might be the complex business logic. It might be my own badly written queries. It might be Prisma. I have been quietly assuming it is Prisma without ever testing that assumption, which is exactly the kind of belief I should not be carrying around.
So this project doubles as the head to head. Same kind of work, different ORM, and a real answer instead of a hunch.
What I Actually Want at the End
Not a shiny portfolio project. I want two specific things.
First, when someone talks about images, containers, networks, bridges, and connecting services across them, I want to follow the conversation completely rather than reconstructing it from context afterwards.
Second, I want a real feel for scale. I know growth is a J curve and no app wakes up to a million users. But fifty thousand to one lakh concurrent users is a level real products actually reach, and being ready for that is a reasonable bar for where I am now.
Syntax Stopped Being the Skill
I have forgotten a lot of syntax. I say that without embarrassment, because at this point syntax is just there. If it disappeared from my head entirely, my output would barely change. AI writes it, and writes it well.
What it does not give you is direction. Vision. The decision about what to build and what to leave out, and the taste to know when something is going to hurt six months from now. That is the part that is still mine to develop, and it is the part I am trying to train with this project.
That is where my head is at right now. The project is one commit old. I will write about it again once something breaks.