Skip to content

Updates

A template you keep taking updates from, not a scaffold you run once.

Your app keeps the kit as a second git remote and takes each update as one commit. No package to install, nothing vendored.

A git graph with two lanes, nuxter-app/kit and your-app. Seven kit commits land on the kit's lane as you scroll, pnpm template:update runs, and they reach your app as one pull request titled chore(template): update to 131069ce30cb. .template-base moves from db3a51ec9e7c to 131069ce30cb. nuxter.app took this exact update on Sep 30, 2026.

01How it works

One remote, one command, one pull request.

The update works out what changed since you last took the kit and applies exactly that.

  1. Once

    Add the kit as a remote.

    Your app shares none of the kit’s history and needs none of it, so main stays linear.

  2. Each update

    Run it on a branch.

    It fetches the kit and applies what changed as a single commit.

  3. Review

    Read it as a pull request.

    The commit lists every kit commit it brings. Reading the diff is the point, and squashing keeps main linear.

Releases

Or take releases.

With no argument the update takes the kit’s main; with a tag, that release. A major tag means you need to act, a minor one applies without your help, and a patch is fixes only.

pnpm template:update v1.4.0

A terminal runs each step in turn: “git remote add template https://github.com/nuxter-app/kit.git”; then “git switch -c template-update-$(date +%Y%m%d)” and “pnpm template:update”, which prints “Template 3217573eb935..db3a51ec9e7c is one new commit. Push the branch and open a pull request.”; then “git log -1 --format=%B”, which shows the commit “chore(template): update to db3a51ec9e7c” and the kit commit it brings.

02Ownership

What is yours and what is the kit’s.

Conflicts are proportional to how much of your code lives in the kit’s files. Keeping to this split is the whole discipline.

  • Yours

    Where your code goes. Every custom/ directory is yours, wherever it sits.

  • Shared

    Both sides write these. starter.config.ts conflicts on purpose: a new option appears and you choose its value.

  • The kit’s

    Extend by configuration. Editing these is signing up to resolve every conflict.

An update sweeps down your app's file tree. The kit's files are updated: server/auth/, server/payments/, server/tenancy/, server/database/schema.ts, modules/, build/, nuxt.config.ts, emails/. Shared files take both sides' changes: starter.config.ts, package.json, pnpm-lock.yaml, scripts/blog/blog.config.mjs. starter.config.ts stops on a new option, payments.pastDueGraceDays, until you choose its value. Your files stay untouched: app/pages/, app/components/, content/, public/, server/jobs/, server/listeners/, server/database/custom/, server/*/adapters/custom/.

03Seams

Adding is a file or a config entry.

Not an edit to shared code that a later update would conflict on. A new language is the one exception.

A background job
fileserver/jobs/<kind>.ts
The filename is the kind.
A listener
fileserver/listeners/<name>.ts
A 00- prefix orders it first.
A table
fileserver/database/custom/schema.ts
Then run pnpm db:generate.
A provider
fileserver/<subsystem>/adapters/custom/<id>.ts
The filename is its id. One matching a shipped adapter replaces it.
A payment plan
keypayments.plans.<plan>
Plus one env var per provider per price. No migration.
A permission
keyaccess.permissions
One string, granted by role or by plan.
A language
filei18n/locales/<code>.json
Plus one i18n.locales entry, a translated copy of en.json, and an entry in four kit tables. The tests name each one still missing.

A new file, crm-sync.ts, drops into server/jobs/ beside the kit's jobs. In your code, enqueue() now offers “crm-sync” as a job kind, read from the filename. Nothing else needs editing.

04Conflicts

When an update conflicts.

Where both sides changed the same lines, the update stops with conflict markers, as any cherry-pick does, and lists the paths.

git add <path>
Keep your resolution.
git rm <path>
Keep a file you deleted.
git cherry-pick --continue
Finish the update commit.
git cherry-pick --abort
Put everything back.

“pnpm template:update” stops and lists the conflicted files: nuxt.config.ts, i18n/locales/en.json. “git add nuxt.config.ts i18n/locales/en.json” keeps the resolution, “git cherry-pick --continue” finishes, and the update is one new commit.

Tips

Three ways to make a hard update easy.

  • 01

    A lockfile conflict

    Keep both sides’ entries in package.json, take the kit’s lockfile, and let pnpm install add your packages back.

  • 02

    Delete rather than gut

    A deleted file conflicts only as modify/delete, which one git rm resolves. A hollowed-out one conflicts on every change.

  • 03

    Take it in pieces

    Pass a tag to take one release at a time, or --no-commit to read the whole update staged before you commit it.

The guide

The whole arrangement, in one document.

Starting an app in a monorepo folder, migrations on two chains, releases, and what to do when an update goes badly.