Deploy your first customer portal →
SuitePortal/NetSuite ORM

Quickstart

Go from zero to querying NetSuite in 5 minutes.

Video Walkthrough

Initialize

npx suiteportal init

This creates a .env file and suiteportal.config.ts in your project root. Fill in your .env with your NetSuite OAuth credentials:

.env
NETSUITE_ACCOUNT_ID=1234567_SB1
NETSUITE_CONSUMER_KEY=your-consumer-key
NETSUITE_CONSUMER_SECRET=your-consumer-secret
NETSUITE_TOKEN_ID=your-token-id
NETSUITE_TOKEN_SECRET=your-token-secret

Never commit your .env file to version control. The init command adds it to .gitignore automatically.

Introspect

Pull your NetSuite schema:

npx suiteportal introspect

This connects to your account, fetches the REST metadata catalog and custom records, and writes:

.suiteportal/
├── schema.json        # Normalized schema (records, fields, relations)
├── relations.json     # Inferred relationships
└── raw-metadata.json  # Raw catalog data

The introspector discovered 142 record types, 1,229 fields, and 6 relations from a standard NetSuite sandbox. Your results will vary based on customizations.

Generate

Generate TypeScript types and a typed client:

npx suiteportal generate

This reads schema.json and writes:

.suiteportal/client/
├── types.ts    # TypeScript interfaces for every record
├── client.ts   # Typed SuitePortalClient
└── index.ts    # Barrel export

Query & Mutate

query.ts
import { createClient } from './.suiteportal/client';
import 'dotenv/config';

const ns = await createClient({
  accountId: process.env.NETSUITE_ACCOUNT_ID!,
  consumerKey: process.env.NETSUITE_CONSUMER_KEY!,
  consumerSecret: process.env.NETSUITE_CONSUMER_SECRET!,
  tokenId: process.env.NETSUITE_TOKEN_ID!,
  tokenSecret: process.env.NETSUITE_TOKEN_SECRET!,
});

const customers = await ns.customer.findMany({
  select: { id: true, companyname: true, email: true },
  take: 10,
});

console.table(customers);
filtered.ts
const activeCustomers = await ns.customer.findMany({
  where: {
    isinactive: { equals: false },
    email: { isNull: false },
  },
  select: { companyname: true, email: true },
  orderBy: { companyname: 'asc' },
  take: 50,
});
count.ts
const total = await ns.customer.count();
console.log(`Total customers: ${total}`);

const active = await ns.customer.count({
  where: { isinactive: { equals: false } },
});
console.log(`Active customers: ${active}`);
create.ts
const newCustomer = await ns.customer.create({
  data: {
    companyname: 'Acme Corp',
    email: 'hello@acme.com',
  },
});
console.log(`Created customer: ${newCustomer.id}`);

That's it — you have typed, autocompletable access to your entire NetSuite schema.

What's Next?

Now that you're up and running, explore the full API:

On this page