Updating the Codebase
Pull new DirectoryLaunch releases into your customized project — add the upstream remote, run the pre-flight, merge a release tag, and keep your branding, config and copy intact.
You own a copy of the boilerplate. Your branding, your pages, your database — none of it lives on our servers. Updates work the way updates work in any git project: we publish a release, you merge it, you resolve the handful of places where your work and ours overlap.
Merge a release tag (v1.15.0), never upstream/main. main is whatever was pushed
most recently, including work in progress. A tag is a version we finished, tested and wrote
release notes for.
Setup — once, right after you clone
pnpm setup:upstreamThat single command does three things, all of them local to your clone:
| It sets up | Why it matters |
|---|---|
The upstream remote + tags | So you can see and merge our releases |
The ours merge driver | Your config/*.config.ts, messages/*.json and public/assets/** survive a merge untouched — no conflict, no lost branding |
git rerere | A conflict you resolve once stays resolved in every future release |
Git ships only three built-in merge behaviours (text, binary, union) — ours is not
one of them, so it has to be configured per clone. The rules live in .gitattributes in your
repo and do nothing until pnpm setup:upstream has run. If you skip it, updates still work;
you just resolve your config files by hand.
Every update
# 1. See what you're getting into. Read-only, changes nothing.
pnpm upgrade:check
# 2. Rehearse it. Performs the merge in a throwaway worktree and reports
# the conflicts, then deletes it. Your repository is never touched.
pnpm upgrade:try --build
# 3. Do it for real, on a branch
git checkout -b update-v1.16.0
git merge v1.16.0
# 4. Resolve whatever conflicts remain (see below)
# 5. Catch up dependencies and database
pnpm install
pnpm db:status
# 6. Prove it compiles AND runs, then merge into your main
pnpm build
pnpm verify:smokepnpm upgrade:try answers "how bad is this going to be?" before you create a branch.
It merges in a disposable git worktree, prints the conflicts and the number of files
affected, optionally builds the result with --build, then throws the worktree away.
Nothing in your repository changes, not even your working tree.
What pnpm upgrade:check tells you
It is the whole reason this is not scary. Before you touch anything, it prints:
- the release you are on and the newest one available
- the changelog entries between the two
- migrations this release adds that your database hasn't got
- env vars this release adds that are missing from your
.env.local - the conflict forecast — the exact list of files you have changed that this release also changes, split into "handled for you" and "you will resolve by hand"
If the forecast is empty, the merge is mechanical.
Resolving conflicts
One rule covers almost everything:
You win in config/, messages/, public/assets/ and app/(marketing)/.
Upstream wins in lib/, app/api/, components/ui/, middleware.ts and supabase/.
git checkout --ours config/site.config.ts # keep your branding
git checkout --theirs lib/supabase/auth-helpers.ts # take our fix
git add <file>After keeping your version of a config file, skim our version for new keys and copy them
across — git diff HEAD...MERGE_HEAD -- config/site.config.ts shows you what we added.
Where conflicts actually happen
Most customizations never conflict, because they aren't in code:
- Colours, typography, radius, shadows — stored in your database, edited at
/admin/design. Nothing to merge. - Card and page layouts, map defaults — same, database-backed.
- Brand name, logos, contact details, plans, feature flags — in
config/, protected by the merge driver. Flags added by a release still reach you:config/features.config.tsholds your overrides, and anything you have not set falls back to the upstream default inconfig/defaults/features.defaults.ts, which does update.
Conflicts come from editing page files. If you rewrote
app/(marketing)/pricing/page.tsx or your Header.tsx, those will conflict whenever we
change them — that's honest, unavoidable git, and the changelog flags those releases with
[ui] so you see it coming.
See What to customize for the full map.
Taking only part of a release
Sometimes you want the API fix and not the redesign. That is possible here because no commit mixes the two — a technical change and a visual change never share a commit.
pnpm upgrade:pick v1.16.0lists the release's commits split into core (lib/, app/api/, components/ui/ — you
never edited these) and customer-facing (marketing pages, layout, styles, config). Then:
git checkout -b core-of-v1.16.0
pnpm upgrade:pick v1.16.0 --applycherry-picks only the core commits and leaves every customer-facing one behind.
A commit you skip comes back the moment you merge that release in full. Partial upgrades are a way to take a security fix today and deal with a redesign next month — not a way to fork permanently.
Does it still run?
pnpm build proves the code compiles. It does not prove a page renders.
pnpm verify:smokeboots the built app and checks that the home page, pricing, FAQ, categories, sign-in, dashboard, admin, the projects API, the sitemap and robots.txt all answer. Routes behind a feature flag you turned off are skipped. It is the difference between "it compiles" and "it works", and it takes about a minute.
Database migrations
Run this after every merge:
pnpm db:statusIt compares the migration files in supabase/migrations/ against a ledger table in your own
Supabase project and prints exactly which ones you still owe. Paste those files into the
Supabase SQL Editor in the order shown.
Run supabase/migrations/0000_migrations_ledger.sql once, then re-run any migration you're
unsure about. Every migration file is idempotent and records itself in the ledger, so
re-running is exactly how an existing project back-fills its history. After that,
pnpm db:status always knows the truth.
Let AI do it
The repo ships an /upgrade slash command for Claude Code. It runs the pre-flight, creates
the branch, merges the tag, applies the who-wins rule file by file, lists pending migrations
and runs lint + typecheck + build:
/upgrade v1.15.0
Using Cursor or another assistant instead? Paste this:
If something goes wrong
You merged on a branch, so nothing is lost:
git merge --abort # mid-merge, undo it
git checkout main && git branch -D update-v1.15.0 # after the factYour production site is unaffected until you merge that branch into main and deploy.
Downloaded a ZIP instead of cloning?
There is no upgrade path from a ZIP — a snapshot has no history to merge against. Move to git once:
git init && git add . && git commit -m "chore: my customized DirectoryLaunch"
git remote add origin https://github.com/you/my-directory.git
git push -u origin main
pnpm setup:upstreamThe first merge after that needs --allow-unrelated-histories and will be noisy. Every
release after it behaves normally.
Do you have to update?
No. A version you deployed keeps working. Merge a release when it contains something you
want, or when it is a security release — those are PATCH bumps in
the changelog and always safe to take.