Theme Development
Use theme pull, theme diff, theme push, and theme watch to sync files between your local machine and a theme installation on your store via the Fork workflow.
Before using these commands, run theme authorize to connect the CLI to your store. See Fork workflow for setup instructions.
Pull
Download all theme files from a theme installation to your local working directory:
nuvemshop theme pull
The CLI fetches every file in the installation and writes them to your current directory, preserving the theme's folder structure:
my-theme/
├── blocks/ ← Block templates (.tpl)
├── config/ ← Settings schema and merchant settings
├── layouts/ ← Main HTML shell
├── locales/ ← Translation files
├── sections/ ← Section templates (.tpl)
├── snippets/ ← Shared partials (.tpl)
├── static/ ← CSS, JS, and other assets
├── templates/ ← Page templates (.json)
└── manifest.json ← Generated by the CLI (not part of the theme)
manifest.json
After pulling, the CLI generates a manifest.json file in your working directory with metadata about the installation:
{
"theme": "ipanema",
"theme_version": "1.0.0",
"forked": false,
"revision_token": "<REVISION_TOKEN>",
"installation_id": "4541834"
}
This file is local only — it's never uploaded when you push or watch. It helps you keep track of which installation and revision your local files came from.
Options
| Option | Description |
|---|---|
--theme-id <id> | Target a specific installation (defaults to the installation linked to this directory in .nuvem) |
--published | Use the store's published theme instead of --theme-id or .nuvem |
--token <token> | Authentication token (CI use ) |
-y | Skip confirmation prompts |
-v | Enable verbose output |
Pulling overwrites local files. If you have uncommitted changes, commit or stash them before pulling.
Push
Upload your local theme files to the theme installation:
nuvemshop theme push
The CLI reads each local file, determines its format based on the file extension, and uploads it to the installation:
| Extension | Upload format |
|---|---|
.json | Parsed and sent as JSON |
.tpl, .css, .js, .svg | Sent as text |
| Everything else | Sent as base64-encoded binary |
Incremental push (smart push)
Before uploading, the CLI compares each local file against its remote version and only uploads the ones that changed. Unchanged files are reported as skipped and no request is made for them — this speeds up pushes and reduces API rate-limit consumption.
The CLI also syncs deletions: files that exist on the remote installation but not in your local directory are removed from the installation during push.
To force every file to be uploaded without remote comparison, use --force:
nuvemshop theme push --force
Options
| Option | Description |
|---|---|
--theme-id <id> | Target a specific installation (defaults to the installation linked to this directory in .nuvem) |
--published | Use the store's published theme instead of --theme-id or .nuvem |
--force | Upload all files without remote comparison (skips unchanged-file detection) |
--token <token> | Authentication token (CI use ) |
-y | Skip confirmation prompts |
-v | Enable verbose output |
What gets uploaded
The CLI uploads all files in your working directory, with these exclusions:
- Dot-prefixed paths — files and directories starting with
.(like.nuvem,.git,.vscode) are always skipped manifest.json— the local manifest is never uploaded- Fork-restricted paths — if the installation is not forked, only
templates/andconfig/settings_data.jsoncan be pushed (see below)
Empty files (zero bytes) are not exclusions — they trigger a per-file upload error, and the overall push reports as failed.
Fork rules
Before pushing, the CLI checks whether the target installation is forked. This determines which files you're allowed to upload:
Non-forked installation — you can only push customization files:
templates/**— page templates (.json)config/settings_data.json— merchant settings
Forked installation — you can push any file in the theme.
Files outside the allowed paths are silently skipped. If you need to modify layouts, sections, blocks, or other theme code, fork the installation first.
Diff
Show what a theme push would change — without uploading anything:
nuvemshop theme diff
The CLI compares the files in your local directory against their remote version on the installation and prints the differences grouped by change type: added, modified, and deleted files (files that exist on the remote but not locally, which push would remove).
Theme diff for theme 4541834 (forked) — 3 changes
Added (1)
+ sections/new-banner.tpl 42 lines
Modified (1)
~ config/settings_data.json
Deleted (1)
- snippets/old-badge.tpl
Unchanged: 214
theme diff follows exactly the same rules as theme push — the upload exclusions and fork rules apply identically. Files that push would skip are reported as skipped, not as changes:
Skipped (not forked, but has changes)— theme code with local changes on a non-forked installation. Push wouldn't upload these files; fork the installation to be able to push them.
Reformatting a .json file (changing indentation or key order) doesn't count as a change. The CLI compares the JSON's semantic content, not the file's bytes, so running a formatter like Prettier won't produce false diffs.
Detailed diff
With --detailed, the CLI also fetches the remote content of modified and deleted files and prints a git-style unified diff for each one, along with added and removed line counts:
nuvemshop theme diff --detailed
Theme diff for theme 4541834 (forked) — 1 change
Modified (1)
~ sections/header.tpl +3 -1
--- remote/sections/header.tpl
+++ local/sections/header.tpl
@@ -12,7 +12,9 @@
<div class="header__logo">
- {{ store.name }}
+ {% if settings.show_logo %}
+ {{ store.name }}
+ {% endif %}
</div>
Unchanged: 214
Some files have no full textual diff, and the CLI states the reason on the file's own line:
| Marker | Meaning |
|---|---|
binary, 12.4 KB → 18.1 KB | Binary file (images, fonts): only sizes are compared |
line endings only | The content is identical; only the line endings differ (CRLF vs LF) |
diff truncated | The file exceeds the 500 patch-line-per-file budget; the diff shown is incomplete |
remote content unavailable | The API didn't return that file's remote content, so it couldn't be compared line by line |
JSON output
Use --json for machine-readable output, useful in CI or scripts:
nuvemshop theme diff --json
nuvemshop theme diff --json --detailed
In JSON mode, stdout holds only the payload — progress messages are suppressed, so you can pipe the result straight into jq:
{
"theme_id": "4541834",
"forked": true,
"detailed": false,
"in_sync": false,
"summary": {
"added": 1,
"modified": 1,
"deleted": 0,
"unchanged": 214,
"skipped_not_forked": 0,
"skipped_push_unsupported": 0,
"read_failures": 0
},
"added": [
{
"path": "sections/new-banner.tpl",
"format": "text",
"lines": 42,
"size_bytes": 1187
}
],
"modified": [{ "path": "config/settings_data.json", "format": "json" }],
"deleted": [],
"skipped_not_forked": []
}
The in_sync field is true only when there are no changes, no files skipped for lack of a fork, and no read failures — that is, when the local directory matches the remote theme. With --detailed, each file entry also carries lines_added, lines_removed, truncated, note, and the unified diff as a string in patch.
Options
| Option | Description |
|---|---|
--theme-id <id> | Target a specific installation (defaults to the installation linked to this directory in .nuvem) |
--published | Use the store's published theme instead of --theme-id or .nuvem |
--detailed | Include a unified diff of what changed inside each file |
--json | Machine-readable JSON output |
--token <token> | Authentication token (CI use ) |
-v | Enable verbose output |
theme diff is read-only: it never uploads, deletes, or modifies files — neither remotely nor locally. That's why it asks for no confirmation and takes no -y.
Watch
Watch your local files and automatically push changes on save:
nuvemshop theme watch
Watch mode monitors your working directory for changes. When you save a file, it's uploaded to the installation immediately. When you delete a file locally, it's deleted from the installation too.
The same upload rules and fork restrictions from theme push apply — watch mode won't upload files that push would skip.
Browser reload
By default, the CLI opens a Puppeteer-driven browser window showing the storefront with the ?theme_installation_id=<id> preview parameter, so you see the installation you're working on (not the productive one). After each successful push or delete, the page is automatically reloaded. Use --no-browser to skip this.
The browser feature uses Puppeteer, which may need to download Chromium on first run. Use --no-browser to skip this and rely on manual browser testing instead.
Options
| Option | Description |
|---|---|
--theme-id <id> | Target a specific installation (defaults to the installation linked to this directory in .nuvem) |
--published | Use the store's published theme instead of --theme-id or .nuvem |
--no-browser | Don't open or reload a browser window |
--token <token> | Authentication token (CI use ) |
-v | Enable verbose output |
Typical development workflow
A common development cycle looks like this:
- Create or clone an installation to work on:
nuvemshop theme create --base-theme ipanema --title "My Theme"ornuvemshop theme clone - Pull the installation files (links the directory to that installation):
nuvemshop theme pull --theme-id ID - Fork if you need to edit theme code:
nuvemshop theme fork - Start watch mode:
nuvemshop theme watch - Edit templates, sections, and settings in your editor — changes sync automatically
- Preview with the auto-reloading browser, or generate a link:
nuvemshop theme preview - Confirm local and remote are in sync before publishing:
nuvemshop theme diff. Watch mode only uploads changes it observed while running, so this catches files you edited before starting watch — or while it was stopped. Add--detailedto inspect anything it reports. - Publish when ready:
nuvemshop theme publish