You are about to build a second thing. A companion app, an admin tool, a public API beside the app that already exists. And the question in front of you is whether that is a second pithy init.
Almost always, it is not.
The question, and its answer
Project structure is what one project looks like, adding a second Worker is usually the real answer, and naming conventions is why the project name is hard to change later.
Do these apps share users or data?
Then it is one project with more Workers, not two projects.
That is the whole rule. Everything below is why it holds and what it costs to get wrong.
Two apps often should share. Two projects never can
A project carries its own migration registry and its own upgrade cadence. Two projects means two of each — so one project’s pithy migrate applies schema the other has never heard of, against a database it does not know about.
And pithy migrate will not let you point them at the same database anyway. Every database in a run is claimed for the project running it, recorded in a row beside the migration ledger, and a database another project owns aborts the run rather than being merged into. Nothing clears that stamp; handing a database over deliberately means dropping the table by hand.
So two projects sharing one database is not a configuration you can reach by accident. It is a configuration you cannot reach at all.
Sharing is expressed in the binding name
Within one project, two Workers share a resource by declaring the same binding name.
Two Workers that both declare DB are backed by one D1. A Worker that wants its own declares COLLAB_DB instead.
That is the entire mechanism, and it is why resource names carry no Worker segment: a feature environment’s resources are named from the project, the branch and the binding, so the binding is what decides what is shared.
It is also why local Miniflare state lives at the project root rather than per Worker — per-Worker state would silently split a shared database in dev and reunite it in production, which is the worst possible place to discover the difference.
Add a Worker, not a project
pithy worker add admin-apiapps/ is the registry. Every command discovers Workers from it, so the new one joins the dev set, the deploy set and the migrate fan-out immediately, with nothing to register.
A second Worker gets its own pithy.config.ts, its own capabilities, its own bindings and its own deploy. It shares what it declares the same binding name for, and nothing else.
Two genuinely separate products can still share an account
They do not need separate Cloudflare accounts, because every resource Pithy provisions is named <project>-<env>-<thing> and the project segment keeps them apart.
Cloudflare’s namespaces are flat and account-wide — D1, KV, R2, Vectorize, Worker scripts, Workflows, the Secrets Store, the token list. None can be partitioned. So the name is the partition, and the project segment is the only thing stopping two projects in one account from adopting each other’s resources.
Provisioning finds a resource by name and reuses it. Without a project segment, find then create means the second project silently inherits the first’s database.
The name is effectively permanent
That name comes from name in the root pithy.config.ts, and nothing else. It is kebab-cased, must start with a letter, and stops at 26 characters.
Once anything is provisioned, it is a contract. Change it and every subsequent command computes names that do not exist: provisioning quietly builds a parallel set beside the running one, teardown finds nothing and reports success, and the original databases, buckets and Worker scripts keep running and keep billing while nothing in the toolchain refers to them any more.
Two guards exist, and neither is an undo:
pithy doctorreports drift — the wiring contradicting the config wholesale — and reports a database whose owner stamp proves another project made it. Both fail the exit code.pithy migraterefuses a database another project owns.
If you must rename, treat it as a migration you perform: move the data, delete the old resources, then change the name.
So when is it two projects?
When the answer to the question at the top is genuinely no.
Different customers. Two products sold to different people, with no user in common and no data either would ever join against.
Different lifecycles. One is a client engagement that ends; the other is yours forever.
Different risk. A prototype you want to be able to delete entirely, without a moment’s thought about what it shares.
If you are hesitating, it is one project. The cost of a second Worker is a directory. The cost of a second project, discovered late, is a data migration.
What pithy init prints, and why
One project per set of apps that share users or data. Another app? Add a worker, not a project.
The name leads every Cloudflare resource this project provisions. Changing it later orphans them.Both halves of that are hard to undo, which is why they are printed above the prompt rather than buried in a guide. This page is the long version of those two sentences.