Staying Up to Date

Pull template updates into your project

Updated August 22nd, 202618 views

Your project keeps a link back to the template it was created from, so improvements made upstream can flow into it. What flows automatically and what you carry by hand are two different things, and the difference matters.

What propagates and what does not

Server packages propagate. Everything under packages/ published as @repo/* is shared. Those updates arrive when the shared packages are bumped.

Client changes do not propagate. Your client is your own copy — usually renamed to apps/<name>-client and diverged from the template's. You apply those changes by hand.

Run the update

From inside your project:

Bash
pnpm update:upstream            # pulls upstream/main
pnpm update:upstream release    # pulls a specific branch

The command shows you the incoming UPSTREAM_RELEASE.md entries before merging, then performs a plain merge pull. Read those notes — each entry carries an adoption checklist marking every change as server (shared) or client (port manually).

Never edit the template's client

Your project contains both apps/client and apps/<name>-client. The first is the template's pristine copy, kept untouched so future pulls merge cleanly. All of your work belongs in apps/<name>-client.

The same applies to mobile: copy apps/mobile to apps/<name>-mobile and work only in the copy.

Always keep your own migrations

This is the one conflict with a single correct answer. Both repositories number migrations from 0000 with completely unrelated content, so an upstream 0003_*.sql has nothing to do with yours, while meta/_journal.json and meta/*_snapshot.json collide by filename despite describing different schemas.

When a merge conflicts anywhere under packages/server/drizzle/src/migrations, keep your side, every timegit checkout --ours on the path. Never hand-merge a _journal.json or a snapshot. Taking the upstream version corrupts the journal and desynchronizes it from your applied schema, and recovering means rebuilding the journal by hand against your live database.

Afterwards, confirm that git status shows no new .sql files you did not write, and that a migration run is a no-op:

Bash
pnpm --filter=@repo/drizzle db:migrate

Schema changes still reach you normally — through schema.ts in the shared package. Take the schema edit, then generate your own migration with pnpm --filter=@repo/drizzle db:generate. Never copy a .sql file from the template.

Port client changes to every client app

When a release note points at a file in apps/client/..., read it as the corresponding file in each of your client apps — and check all of them. The common failure is porting into the app that kept the template's name while a renamed sibling silently keeps the old code.

Finish the cleanup

Porting a change is not done when the new code is in place.

  • If an entry replaces a helper you had locally, delete your local copy and re-point its imports. A leftover duplicate keeps the old bug alive at every call site still importing it.

  • Grep for the old symbol across the whole repository, not just the app you edited.

  • Where a note mentions a behaviour change, re-check each call site. Identical signatures with different output type-check perfectly.

Then run the checks:

Bash
pnpm lint
pnpm test

A clean type-check on its own is not evidence that a port landed correctly — the tests are what tell you.