File Cabinet Pull
Download SuiteScript files from the NetSuite file cabinet to your local project.
The pull command downloads files from the NetSuite file cabinet to your local machine. It uses SuiteQL for inventory (fast, paginated listing of all remote files) and the SuiteCloud CLI for download (batched file:import calls with automatic retry and resume).
Quick Start
# See what's in the file cabinet
npx suiteportal pull --list
# Download all SuiteScripts
npx suiteportal pull --folder SuiteScripts
# Preview what would be downloaded
npx suiteportal pull --folder SuiteScripts --dry-runThat's it. On first run, SuitePortal automatically:
- Detects your existing SuiteCloud CLI authentication
- Scaffolds a SuiteCloud project at
.suiteportal/sdf/ - Inventories all remote files via SuiteQL
- Downloads them in batches of 20 via
suitecloud file:import
You need the SuiteCloud CLI installed (npm install -g @oracle/suitecloud-cli) and authenticated (suitecloud account:setup). You also need a .env with OAuth credentials for the SuiteQL inventory step — run suiteportal init if you haven't already.
How It Works
SuiteQL inventory → diff against manifest → batched file:import → checkpoint- Inventory — Queries the
mediaitemfolderandfileSuiteQL tables to build a complete listing of remote files. Pagination is automatic (1000 rows per page), so even large file cabinets are fully inventoried. - Auto-setup — If no SuiteCloud project is found, SuitePortal detects your existing auth ID (from
suitecloud account:manageauth --list) and scaffolds a project at.suiteportal/sdf/wired to it. No manualproject:createoraccount:setupneeded. - Diff — Compares the remote inventory against a local manifest to identify new and modified files. Unchanged files are skipped.
- Batch import — Splits the file list into batches (default: 20 files each) and runs
suitecloud file:importfor each batch. If a batch fails, it retries each file individually so one bad file doesn't block the rest. - Checkpoint — The manifest is saved after each batch, so interrupted pulls resume where they left off.
NetSuite's REST API and SuiteQL do not expose file content — only metadata (name, folder, size, type, url). The SuiteCloud CLI is the only standard way to download file content without deploying custom scripts.
Commands and Flags
| Flag | Description |
|---|---|
--list | Inventory remote files without downloading |
--folder <path> | Filter to a specific file cabinet folder prefix |
--project <dir> | Path to an existing SuiteCloud project (default: auto-scaffolded) |
--force | Re-download all files, ignoring the manifest |
--dry-run | Show what would be downloaded without downloading |
List Remote Files
npx suiteportal pull --listPrints a summary of all remote files grouped by folder, with file counts and sizes:
Folder Files Size
────────────────────────────────────────────────── ────── ──────────
SuiteScripts/RSM/SS2 37 890 KB
SuiteScripts/RSM/SS2/RecordTypes 12 240 KB
SuiteScripts/RSM/SS2/NFT-SS2-7.2.0 10 1.1 MB
Total: 181 files (3.2 MB)The --list flag only runs the SuiteQL inventory — it does not require the SuiteCloud CLI.
Dry Run
npx suiteportal pull --folder SuiteScripts --dry-runShows which files would be downloaded (new or modified) without actually importing them:
+ SuiteScripts/Custom/SS2/UE_PurchaseOrder.js
+ SuiteScripts/Custom/SS2/RecordTypes/PurchaseOrder.js
~ SuiteScripts/Custom/SS2/Lib_Helpers.js+ indicates new files, ~ indicates modified files.
Filter by Folder
npx suiteportal pull --folder SuiteScripts/Custom/SS2/RecordTypesOnly pulls files under the specified file cabinet folder. The path matches as a prefix, so SuiteScripts includes all subfolders.
Force Re-download
npx suiteportal pull --force --folder SuiteScriptsIgnores the manifest and re-imports every file, even if unchanged.
Use an Existing SuiteCloud Project
npx suiteportal pull --project /path/to/my-sdf-project --folder SuiteScriptsIf you already have a SuiteCloud project with authentication configured, point to it with --project. Files are imported into that project's src/FileCabinet/ directory.
Configuration
Add a pull section to your suiteportal.config.ts to set defaults:
export default {
pull: {
// Only pull from this folder (and subfolders)
folder: 'SuiteScripts',
// File types to include (default: JAVASCRIPT, JSON, PLAINTEXT, XMLDOC)
fileTypes: ['JAVASCRIPT', 'JSON', 'PLAINTEXT', 'XMLDOC'],
// Files per suitecloud file:import batch (default: 20)
batchSize: 20,
// Path to an existing SuiteCloud project (default: auto-scaffolded at .suiteportal/sdf/)
// projectDir: './my-sdf-project',
},
};CLI flags override config file values.
Output Structure
Downloaded files are placed in the SuiteCloud project's src/FileCabinet/ directory, mirroring the NetSuite folder structure:
.suiteportal/sdf/ ← auto-scaffolded project
├── project.json ← auth link (auto-detected)
├── suitecloud.config.js
├── .suiteportal-pull-manifest.json ← pull state
└── src/
├── manifest.xml
├── deploy.xml
└── FileCabinet/
└── SuiteScripts/
├── Custom/SS2/
│ ├── UE_PurchaseOrder.js
│ ├── CS_SalesOrder.js
│ └── RecordTypes/
│ ├── PurchaseOrder.js
│ └── SalesOrder.js
└── SelectLines_CS.jsManifest and Resume
Pull state is tracked in .suiteportal-pull-manifest.json inside the SuiteCloud project directory. This file records:
- Which files have been imported
- When each file was last pulled
- The remote
lastmodifieddateat time of pull
On subsequent pulls, only new and modified files are downloaded. If a pull is interrupted (network error, Ctrl+C, governance limit), the next run picks up where it left off — no files are re-downloaded.
Batch Strategy
The core problem with suitecloud file:import is that importing too many files at once hits NetSuite governance limits. SuitePortal solves this by:
- Inventory first — SuiteQL gives the complete file list without governance issues
- Smart batching — files are grouped into batches of 20 (configurable) per import call
- Fallback to individual — if a batch fails, each file in the batch is retried individually
- Checkpoint after each batch — progress is saved so you can resume after failures
For a file cabinet with 500 files, this means ~25 small import calls instead of 1 massive import that fails.
Auto-Setup Flow
When you run suiteportal pull for the first time:
- Checks for SuiteCloud CLI — if
suitecloudisn't on PATH, prints install instructions and exits - Checks for existing project — looks in the current directory, then
.suiteportal/sdf/ - Detects auth — runs
suitecloud account:manageauth --listto find your configured auth ID - Scaffolds project — creates a minimal SuiteCloud project at
.suiteportal/sdf/withproject.jsonwired to your auth ID
On subsequent runs, the project is reused automatically.
If you have multiple auth IDs configured, SuitePortal uses the first one. To use a different one, either point --project at a project configured with the desired auth, or set pull.projectDir in your config.
File Types
By default, the inventory includes these file types:
| File Type | Description |
|---|---|
JAVASCRIPT | SuiteScript files (.js) |
JSON | JSON configuration files |
PLAINTEXT | Plain text files (.txt) |
XMLDOC | XML documents |
Configure additional types in suiteportal.config.ts:
export default {
pull: {
fileTypes: ['JAVASCRIPT', 'JSON', 'PLAINTEXT', 'XMLDOC', 'HTMLDOC', 'STYLESHEET'],
},
};