Deploy your first customer portal →
SuitePortal/NetSuite ORM

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-run

That's it. On first run, SuitePortal automatically:

  1. Detects your existing SuiteCloud CLI authentication
  2. Scaffolds a SuiteCloud project at .suiteportal/sdf/
  3. Inventories all remote files via SuiteQL
  4. 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
  1. Inventory — Queries the mediaitemfolder and file SuiteQL tables to build a complete listing of remote files. Pagination is automatic (1000 rows per page), so even large file cabinets are fully inventoried.
  2. 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 manual project:create or account:setup needed.
  3. Diff — Compares the remote inventory against a local manifest to identify new and modified files. Unchanged files are skipped.
  4. Batch import — Splits the file list into batches (default: 20 files each) and runs suitecloud file:import for each batch. If a batch fails, it retries each file individually so one bad file doesn't block the rest.
  5. 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

FlagDescription
--listInventory 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)
--forceRe-download all files, ignoring the manifest
--dry-runShow what would be downloaded without downloading

List Remote Files

npx suiteportal pull --list

Prints 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-run

Shows 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/RecordTypes

Only 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 SuiteScripts

Ignores 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 SuiteScripts

If 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:

suiteportal.config.ts
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.js

Manifest 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 lastmodifieddate at 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:

  1. Inventory first — SuiteQL gives the complete file list without governance issues
  2. Smart batching — files are grouped into batches of 20 (configurable) per import call
  3. Fallback to individual — if a batch fails, each file in the batch is retried individually
  4. 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:

  1. Checks for SuiteCloud CLI — if suitecloud isn't on PATH, prints install instructions and exits
  2. Checks for existing project — looks in the current directory, then .suiteportal/sdf/
  3. Detects auth — runs suitecloud account:manageauth --list to find your configured auth ID
  4. Scaffolds project — creates a minimal SuiteCloud project at .suiteportal/sdf/ with project.json wired 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 TypeDescription
JAVASCRIPTSuiteScript files (.js)
JSONJSON configuration files
PLAINTEXTPlain text files (.txt)
XMLDOCXML documents

Configure additional types in suiteportal.config.ts:

export default {
  pull: {
    fileTypes: ['JAVASCRIPT', 'JSON', 'PLAINTEXT', 'XMLDOC', 'HTMLDOC', 'STYLESHEET'],
  },
};

On this page